Why we moved our design tokens to OKLCH
HSL lies about lightness. OKLCH doesn't. What changed when we rebuilt a brand palette on a perceptually uniform color space.
Pick a yellow and a blue with the same HSL lightness and put them side by side: the yellow glows, the blue sulks. HSL's "lightness" is a lie your design system tells you. OKLCH fixes that — its L actually corresponds to how bright a colour looks.
The practical wins
Derived shades keep their perceived weight. Hover states, muted variants and chart ramps can be generated by nudging one axis:
:root {
--brand: oklch(0.902 0.1925 108.42);
/* Same perceived lightness steps, one axis changed */
--chart-1: oklch(0.902 0.1925 108.42);
--chart-2: oklch(0.768 0.17 108.42);
--chart-3: oklch(0.648 0.145 108.42);
}And because OKLCH addresses colours outside sRGB, modern screens get the saturated P3 version of your brand colour while older ones clamp gracefully.
Gotchas
- Fallbacks are automatic in modern build chains — Lightning CSS
compiles
oklch()down tolab()/hex pairs for older browsers. - Don't eyeball chroma. Chroma limits differ per hue and lightness; validate that your combination is displayable instead of guessing.
- Keep tokens semantic. The space solves perception, not naming.
--brandbeats--yellow-500the day the brand changes.
We now define every colour in the system as OKLCH behind semantic tokens, and components never touch a raw value. One file to rebrand, zero visual surprises.
Get the next one in your inbox
New articles, videos and the occasional engineering note — a short mail when there’s something worth reading, nothing else.