Add css functions and mixins post amd delete old test posts. prs site is basically done now !!

vielle.dev ff14882c 721c08b0

verified
Changed files
+391 -113
src
src/content/blog/assets/mixins.png

This is a binary file and will not be displayed.

src/content/blog/assets/nested.png

This is a binary file and will not be displayed.

src/content/blog/assets/test.png

This is a binary file and will not be displayed.

+391
src/content/blog/css-functions-and-mixins.md
··· 1 + --- 2 + title: CSS functions and mixins 3 + bio: tl;dr and my 2 cents 4 + banner: mixins.png 5 + pub: 2000-01-01 6 + --- 7 + 8 + The CSS `@function` rule is now available in chrome 139, with a definition for `@mixin` in the editors draft. (Referenced [First Public Working Draft](https://www.w3.org/TR/2025/WD-css-mixins-1-20250515/), Referenced [Editors Draft](https://drafts.csswg.org/css-mixins/)) 9 + I wanted an excuse to read into a spec, and this seems quite an interesting one so I thought why not write a post about it! (this is definitely not also because I need something to post when i deploy my site so it doesn't look empty lmao) 10 + 11 + > _All ye who travel beyond this point, head this warning_: 12 + > This spec got hands and idk how to shut up so this is a long ish post. Sorry! Also sorry about any syntax highlighting bugs. This is an experimental spec and I'm using nesting too, which might cause visual bugs with my syntax highlighter. This should resolve with time though. I hope. 13 + 14 + --- 15 + 16 + ## 1. What's in a function anyway? 17 + 18 + CSS has a bunch of functions (`rgb`, `anchor`, `blur`, and `var` to name a few), which are all free of side effects and consistent\*, but are fully defined in the spec, without any way for developers to specify their own functions. 19 + 20 + \*CSS random, as discussed in [this webkit post](https://webkit.org/blog/17285/rolling-the-dice-with-css-random/), isn't always consistent (it's a random function after all) however it is 1) not in anything except safari TP so I'm not gonna count it and 2) I Cant Find Any Actual Spec. So. also not gonna count it. 21 + 22 + Imagine this css: 23 + 24 + ```css 25 + h1 { 26 + font-size: 3em; 27 + 28 + @media (max-width: 1200px) { 29 + font-size: 2em; 30 + } 31 + @media (max-width: 600px) { 32 + font-size: 1em; 33 + } 34 + } 35 + 36 + img { 37 + width: 1000px; 38 + 39 + @media (max-width: 1200px) { 40 + width: 800px; 41 + } 42 + @media (max-width: 600px) { 43 + width: 450px; 44 + } 45 + } 46 + 47 + .screen-mode::after { 48 + content: "desktop"; 49 + 50 + @media (max-width: 1200px) { 51 + content: "tablet"; 52 + } 53 + @media (max-width: 600px) { 54 + content: "mobile"; 55 + } 56 + } 57 + ``` 58 + 59 + While this isn't the most realistic css (the font size probably doesn't need to change, the image could be more fluid with %/vw/vh/etc, and you would basically never need to do that with `::after`), it's useful for demonstration of a potentially useful function. 60 + 61 + Below we're going to start defining a function which will take in 1 to 3 parameters, and return values matching the media queries above (ie: if it matches 600px it'll return `--mobile`, falling back to `--tablet` if not defined, and falling back to `--desktop` if thats not defined, etc) It'll make more sense when we define it 62 + 63 + ```css 64 + @function --media(--desktop, --tablet, --mobile) { 65 + /* function body here */ 66 + } 67 + ``` 68 + 69 + This CSS defines a new function, which we could later use like `width: --media(1000px, 800px, 450px)`, however currently the arguments don't matter, and the result is the "guaranteed-invalid value" (same as if you use something like `var(--not-set)` without a fallback) and so won't work. 70 + 71 + For this to be useful, we need a `result`. `result` is a property which can be used within `@function` to define the output of the function. A simple negation function could look something like this: 72 + 73 + ```css 74 + @function --negate( 75 + --value type(<length> | <number> | <length-percentage>): initial 76 + ) { 77 + result: calc(-1 * var(--value)); 78 + } 79 + ``` 80 + 81 + But wait, I hear you ask, what does all that stuff after `--value` mean??? 82 + CSS functions let you define a type and default value for a function. I've used the type definition of `type(<length> | <number> | <length-percentage>)` to tell the browser that if you pass in a value that isn't either a length, number, or length percentage, then it should treat the value as invalid. (note: browser dev tools for this aren't the _best_ right now, but this will come with time) 83 + The `: initial` 84 + 85 + Going back to our `--negate` function, usage like `--negate(10px)` returns `-10px`, and `--negate(-5%)` returns `5%`, however something like `--negate(twenty)` wouldn't work, as `twenty` is not of type number, and even if we didn't have the type, `calc(-1 * twenty)` makes no sense, and would be invalid. 86 + 87 + So we can see that `result` simply defines the output for the function. This is great for making complex, repeated calculations more legible, and for repeating reused syntax (`result: 10px 10px 5px var(--colour, black)` could be used for a `--shadow` function), but doesn't solve our function, which does media query things. Thankfully, `@function` supports `@media` inside it (and some other @rules) 88 + 89 + ```css 90 + @function --media( 91 + --desktop, 92 + --tablet: var(--desktop), 93 + --mobile: var(--tablet) 94 + ) { 95 + result: var(--desktop); 96 + 97 + @media (max-width: 1200px) { 98 + result: var(--tablet); 99 + } 100 + @media (max-width: 600px) { 101 + result: var(--mobile); 102 + } 103 + } 104 + ``` 105 + 106 + This above code returns desktop, unless the screen is <1200px, in which case it returns tablet, and if the screen is <600px, it returns mobile. If mobile isn't defined, it's the same as tablet, and if tablet isn't defined, its the same as desktop. 107 + 108 + We can now replace our original example with an updated `--media()` function! 109 + 110 + ```css 111 + h1 { 112 + font-size: --media(3em, 2em, 1em); 113 + } 114 + 115 + img { 116 + width: --media(1000px, 800px, 450px); 117 + } 118 + 119 + .screen-mode::after { 120 + content: --media("desktop", "tablet", "mobile"); 121 + } 122 + ``` 123 + 124 + Another thing worth noting about `@function` is that it can access custom properties from the "calling scope": 125 + 126 + ```css 127 + @function --double--x() { 128 + result: calc(2 * var(--x)); 129 + } 130 + 131 + h1 { 132 + --x: 2em; 133 + font-size: --double--x(); 134 + } 135 + ``` 136 + 137 + Keep in mind that arguments "shadow" the custom properties. 138 + 139 + ```css 140 + @function --double--x(--x) { 141 + result: calc(2 * var(--x)); 142 + } 143 + 144 + h1 { 145 + --x: 2em; 146 + /* wont work because --x is not passed in */ 147 + font-size: --double--x(); 148 + } 149 + ``` 150 + 151 + If you want to be able to use custom properties when no argument is provided, you can set the default value to "inherit" 152 + 153 + ```css 154 + @function --double--x(--x: inherit) { 155 + result: calc(2 * var(--x)); 156 + } 157 + 158 + h1 { 159 + --x: 2em; 160 + /* works because --x is inherited from context */ 161 + font-size: --double--x(); 162 + } 163 + ``` 164 + 165 + As you can see; there's quite a lot to functions. If you want more specific and detailed information, or anything not explained here (like how to pass in comma seperated lists or more specific type syntax), your best bet is to reference the spec (and eventually MDN) and just experiment! 166 + 167 + ## Mixin? Mixin what? Mixin. Now. 168 + 169 + (I don't know what the title means and at this point I'm too afraid to ask [my brain]) 170 + 171 + As mixins are experimental and subject to change (and have no browser support yet) I'm not going to go into masses of detail like I did with `@function`, and instead just hit the highlights. 172 + Also these examples might be stupid I'm not justifying the feature its Fine 173 + 174 + ### Mixin Arguments 175 + 176 + The most basic mixin definition is like this: 177 + 178 + ```css 179 + @mixin --copy-paste() { 180 + /* properties go here */ 181 + } 182 + ``` 183 + 184 + `@mixin` is defined in basically the same way as `@function`: 185 + 186 + ```css 187 + @mixin --horrible( 188 + --background <color>: red, 189 + --accent <color>: blue, 190 + --scale <number>: 1 191 + ) { 192 + /* properties go here */ 193 + } 194 + ``` 195 + 196 + Unlike `@function`, mixin properties are exposed under `env()`, not `var()`, so theres no risk of conflict and the properties arent injected outside the body. If you want values to be able to be accessed from outsize the mixin, you can still use custom properties. 197 + 198 + Mixins can also accept blocks of properties as an argument: 199 + 200 + ```css 201 + @mixin --mobile(@contents) { 202 + /* properties go here */ 203 + } 204 + ``` 205 + 206 + And can accept both at the same time: 207 + 208 + ```css 209 + @mixin --weird(--bg: <color>, @contents) { 210 + /* properties go here */ 211 + } 212 + ``` 213 + 214 + ### Mixin Application 215 + 216 + When no args are passed/needed, you can do this to `@apply` a mixin: 217 + 218 + ```css 219 + body { 220 + @apply --copy-paste; 221 + } 222 + ``` 223 + 224 + Passing arguments is basically the same as custom functions: 225 + 226 + ```css 227 + body { 228 + @apply --horrible(orange, purple, 2); 229 + } 230 + ``` 231 + 232 + `@content` can be used like this: 233 + 234 + ```css 235 + body { 236 + @apply --mobile { 237 + background-color: red; 238 + } 239 + } 240 + ``` 241 + 242 + And you can use arguments and `@contents` together like this: 243 + 244 + ```css 245 + body { 246 + @apply --weird(red) { 247 + color: blue; 248 + } 249 + } 250 + ``` 251 + 252 + ### Mixin Bodies 253 + 254 + Mixin bodies are **_basically_** inserted wherever `@apply` is used. Just list the properties you want to include inside the mixin and they'll be inserted, including custom properties. 255 + 256 + You can access the arguments to the function via a dashed indent in `env()`: 257 + 258 + ```css 259 + @mixin --horrible( 260 + --background <color>: red, 261 + --accent <color>: blue, 262 + --scale <number>: 1 263 + ) { 264 + background-color: env(--background); 265 + color: env(--accent); 266 + border: calc(5px * env(--scale)) groove env(--accent); 267 + border-radius: 50%; 268 + float: right; 269 + &:hover { 270 + background-color: env(--accent); 271 + color: env(--background); 272 + border-color: env(--background); 273 + } 274 + } 275 + ``` 276 + 277 + You can insert whatever properties were passed into a mixin using the `@contents` at rule: 278 + 279 + ```css 280 + @mixin --mobile(@contents) { 281 + @media (max-width: 600px) { 282 + @contents; 283 + } 284 + } 285 + ``` 286 + 287 + You can also provide a default value for `@contents`: 288 + 289 + ```css 290 + @mixin --mobile(@contents) { 291 + @media (max-width: 600px) { 292 + @contents { 293 + &::before, 294 + &::after { 295 + display: block; 296 + background-color: red; 297 + color: black; 298 + contents: "Warning: Unused `@apply --mobile`. Include a declaration list"; 299 + } 300 + } 301 + } 302 + } 303 + ``` 304 + 305 + If no declaration list is passed to the mixin, the fallback will be used instead. 306 + 307 + In a mixin, if you use custom properties, they are inserted along with other properties. This is useful if you want values to be accessible to the user (ie: exposing a colour derived from input for use elsewhere), but also pollutes the namespace. As such, you should avoid using custom properties when you don't explicitly want the user to read/override things. As such, use `@env` to define environment variables scoped to the mixin body. 308 + 309 + ```css 310 + @mixin --mix-colour(--col1, --col2) { 311 + @env --mix: color-mix(in oklab, env(--col1), env(--col2)); 312 + color: env(--mix); 313 + } 314 + ``` 315 + 316 + In this example `env(--mix)` is only avaliable inside the `--mix-colour` body, and doesnt pollute the calling context. 317 + 318 + Thats about the gist on mixins, its very new and experimental and has 0 implementation so go read the spec yourself lol 319 + 320 + ## Listen to me speak now please thank you 321 + 322 + First note: I think these are really good so far, maybe some slight tweaks needed for mixins. I will say that with mixins I'm not the BIGGEST fan of using `env()`, but if I remember correctly it originally started with an `@result` at rule or something like that, so I'm pretty sure theres a reason we got an `@env` etc instead. That said I dont really mind `env()` to much so its Fine lmao. 323 + 324 + I also think its worth considering named `@contents` blocks instead, maybe something like this: 325 + 326 + ```css 327 + @mixin --media(--desktop @contents, --mobile @contents) { 328 + @media not (max-width: 600px) { 329 + @contents --desktop { 330 + desktop-fallback: here; 331 + } 332 + } 333 + @media (max-width: 600px) { 334 + @contents --mobile { 335 + mobile-fallback: here; 336 + } 337 + } 338 + } 339 + 340 + body { 341 + @apply --media() { 342 + desktop-properties: here; 343 + } { 344 + mobile-properties: here; 345 + } 346 + } 347 + } 348 + ``` 349 + 350 + The current syntax of having a single trailing `@contents` and single trailing `{/*properties*/}` for cases where only one `@contents` is needed. This might need some tweaking for legibility etc, but some way to add multiple `@contents` blocks would be nice. I agree with the enforcing of them being at the end of the argument list though. 351 + 352 + Another suggestion, which may be defered to level 2: expose functions to CSS houdini. 353 + 354 + For example, something like this: 355 + 356 + ```js 357 + // index.js 358 + CSS.functions.addModule("css-arrays.js"); 359 + ``` 360 + 361 + ```js 362 + // css-arrays.js 363 + registerFunction( 364 + "--get", 365 + class { 366 + static get arguments() { 367 + return [ 368 + { 369 + type: "<string>#", 370 + }, 371 + { 372 + type: "<number>", 373 + default: 0, 374 + }, 375 + ]; 376 + } 377 + 378 + eval(array, index) { 379 + return array[index]; 380 + } 381 + }, 382 + ); 383 + ``` 384 + 385 + `css-arrays.js` would run in a custom Worklet environment, most likely a plain ECMAScript environment with no APIs, which may be created and destroyed on each call. It wouldn't open the door to advanced functionality like `--anchor`, but could make "simpler" functions ponyfillable, like arrays/objects, or even things like `color-mix`. 386 + 387 + This is NOT a formal proposal, just a suggestion. Might make an issue in the repo later if I can be bothered. 388 + 389 + --- 390 + 391 + Anyway, to conclude: I'm extremely happy with the reccomended API right now, and I would be happy to see this or something very similar land in browsers. Also let us do functions with JS it would be v good for ponyfilling.
-6
src/content/blog/nested/test.md
··· 1 - --- 2 - title: Testing nesting 3 - bio: nested !! 4 - banner: nested.png 5 - pub: 2025-08-13 6 - ---
-107
src/content/blog/test.md
··· 1 - --- 2 - title: Test 3 - bio: A Test Post 4 - banner: test.png 5 - pub: 2025-08-13 6 - --- 7 - 8 - ## Header 2 9 - 10 - Paragraph 11 - 12 - Second paragraph with *italics*, **bold**, and ***both*** 13 - 14 - ## Header 2 15 - ### Header 3 16 - 17 - theres some `inline code` 18 - and heres an html 19 - ```html 20 - <span class="gay">Code Block</span> 21 - <!-- with a really super duper long comment aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa --> 22 - ``` 23 - 24 - ```js 25 - smallLine() 26 - ``` 27 - 28 - ## Header 2 29 - ### Header 3 30 - #### Header 4 31 - 32 - > albert einstein said that or smthn 33 - > idk what that guy said 34 - > he was inertia or smthn 35 - > smart meters 36 - 37 - --- 38 - 39 - ol lorem ipsum dolor amet dolor sit 40 - 41 - 1. lists 42 - 2. ordered 43 - 1. nested 44 - 2. properly 45 - 1. testing 46 - 1. testing 47 - 1. testing 48 - 1. testing 49 - 1. testing 50 - 1. testing 51 - 1. testing 52 - 1. testing 53 - 1. testing 54 - 1. testing 55 - 1. testing 56 - 1. testing 57 - 1. testing 58 - 1. testing 59 - 1. testing 60 - 1. testing 61 - 1. testing 62 - 1. testing 63 - 1. testing 64 - 1. testing 65 - 1. testing 66 - 1. testing 67 - 1. testing 68 - 3. see 69 - 3. can go back out too 70 - 1. numbers dont matter 71 - 1. just gotta be there 72 - 73 - ul lorem ipsum dolor sit amet dolor sit 74 - 75 - - unordered 76 - - lists 77 - - nested 78 - - deeper 79 - - unnesting 80 - - see 81 - 82 - cl lorem ipsum dolor sit amet amet dolor sit 83 - 84 - - [ ] incomplete 85 - - [ ] task 86 - - [ ] relies on 87 - - [x] complete task 88 - - [x] eventually 89 - - [x] done 90 - 91 - ml lorem ipsum amet dolor sit 92 - 93 - - unordered 94 - 1. then ordered 95 - - then unordered 96 - - [ ] then a list 97 - - [x] which isnt done yet 98 - 99 - [heres a link](/) <https://example.com> <example@example.com> 100 - ![an image](./assets/nested.png) 101 - 102 - ## h2 103 - 104 - | Column | Col2 | 105 - | ------: | :------ | 106 - | testing | testing | 107 - | empty cells |