#design
16 posts
CSS is getting functions and conditionals: @function and if()
Two new pieces of CSS — custom functions and inline conditionals — remove the copy-paste that every component accumulates. Neither is Baseline yet, but both are worth reading early.
text-box-trim is usable now: cut the dead space around headings
Line boxes are always taller than the glyphs, so that half-leading above a heading used to be fixed with negative margins. text-box-trim does it properly.
Putting a Three.js island inside a static site
The isle page downloads only its own script. The scene is computed at runtime, Three.js stays in that page's chunk, and the first HTML response carries an empty stage.
Volume without a modelling tool: triangulating an island by hand
The rock on this island is not exported from a modelling tool. It is five irregular rings stitched together at runtime, and vertex colours plus flat shading are enough to make it read as stone.
Lighting one scene: three lamps and a shadow map computed once
A hemisphere light for ambience, a key light for direction and shadow, a rim light to pull the island off the background — and seven point lights that only add glow.
Water from two shaders: a pool, a stream and a waterfall
There is no water simulation on the island and no reflections. Two ShaderMaterials cover all of it, one lying flat and one falling, sharing a single time and night uniform.
sibling-index() and sibling-count(): CSS finally knows which one it is
Firefox 154 brings these two functions to Baseline. They return the current element's position among its siblings and the total sibling count, so staggered animation, ordered colours, and even sizing can be computed in CSS instead of an inline variable per element.
The autocorrect attribute: giving the page a say in auto-correction
Chrome 152 supports the global autocorrect attribute, Safari and Firefox had it already, and so it reaches Baseline. How it differs from spellcheck, why it spent years as a vendor prefix, and when you should turn it off.
Using @layer to make CSS precedence a declared order, not a specificity fight
Runaway styles come from everyone solving problems by adding specificity. Cascade layers make the order explicit: between layers only order matters, and specificity applies within a layer.
Anchors hidden behind a sticky header: one scroll-padding-top for the whole site
A sticky header covers every anchor target. scroll-margin per heading always misses one; scroll-padding-top on the scroll container does not, fed by the real header height.
Use the native dialog element: you get more than you think
A hand-rolled modal needs a focus trap, ESC handling, scroll locking and focus restore. Native dialog with showModal has all of it plus ::backdrop, and one style rule as the price.
Dark mode forms stay white: color-scheme is the switch
Painting a dark background does not darken native controls. Select popups, date pickers and autofill follow color-scheme; accent-color only reaches checkboxes and sliders.
Design tokens: one file that runs the whole site
Why every colour, spacing step and corner radius lives in _tokens.scss — and why changing this site's entire visual direction only touched two files.
Manual i18n: what hand-rolling three languages costs
I hand-rolled this site's i18n instead of using Astro's built-in config. Here is why, and exactly where the cost shows up — two 404 incidents and a blog that was half translated.
Turning screen-printing limits into design tokens
This site's visual direction is Riso screen printing. What I actually built was the printing constraints as tokens, so retheming touched two files and no component changed.
A theme-switch ripple with the View Transitions API
A circle growing from the click point reveals the new theme. The radius must reach the farthest corner, and the custom properties must be cleaned up or they leak into the next switch.
