Design
Dark mode without a toggle
2 min readStatic Core
This site ships no JavaScript, and a colour-scheme toggle needs some: it has to read a stored preference, apply it before the first paint, and remember it. The operating system already knows the answer, so the site asks it instead.
Dark mode is one file, not a pass over the site
Every class string the site uses is a named export in a single design file, and components read them. A page never writes a class at all. That constraint exists for other reasons, but it is what makes a second colour scheme cheap: each colour token states its light value and then its dark variant, in one place, side by side.
Adding the scheme was therefore an edit to one file rather than a pass over every component. Nothing had to be found, because nothing had spread.
The contrast trap on a raised surface
Both schemes are held to the stricter of the two contrast standards — 7:1 rather than 4.5:1 — and the dark scheme is where that starts to bite in a way the light one does not.
A card sits one step lighter than the page so it reads as raised. That step is enough to move secondary text below the line: the same grey reaches 7.87:1 on the page's background and only 6.96:1 on a card's. So there are two muted tokens, one for the page and one for a surface, and text on a card goes a step lighter to stay above the threshold.
That is not a subtlety a component can work out for itself, which is why it is written into the token names rather than left to whoever adds the next card.
The one thing no utility class expresses
The CSS color-scheme property, set to light dark, is what makes scrollbars, form controls and the browser's own default surfaces follow the scheme. Without it a dark page keeps a bright scrollbar down its edge.
No utility class says it, so it lives in the stylesheet entry point with the handful of other rules that are genuinely global — a pseudo-element, a print block. That split is the only reason any of this site's appearance is described outside the design file, and keeping the list short is what keeps the file worth trusting.
Key takeaways
- If every class string lives in one file, a second colour scheme is one file's worth of work
- A raised surface changes the contrast maths: secondary text on a card needs its own token
- The color-scheme property is not a utility class, and without it the scrollbars give you away