oklch(from …)
Five colours out of one token
one token in — tint, base, shade, muted, complement out
CaveatThe channel names are not variables you set — they are the source colour taken apart. l, c and h arrive already holding the token’s own values, and calc() on them is the whole trick. Do the arithmetic in oklch even when the token is an sRGB hex: a lightness nudge there is perceptually even, where the same nudge through rgb() lands differently on a blue than on a yellow. Hue wraps on its own, so h + 180 is the complement with no modulo — but lightness and chroma clamp silently: calc(l + .3) on an already-light token quietly pins at white, and a palette built on additions looks fine right up until someone feeds it a token near the edge. Multiply where the token is not yours to predict.
FallbackSame law as every colour function this decade: an engine that cannot parse it drops the declaration whole, not just the value. Each swatch above declares the plain token first and the derived colour second, so a museum engine shows five copies of the base blue — wrong, but coloured and legible. Order the two declarations the other way round and the fallback wins everywhere, and the palette never existed.
:root { --brand: #6fa8dc; }
.tag {
/* plain first, derived second */
background: #6fa8dc;
background: oklch(
from var(--brand) calc(l - .17) c h);
}
/* multiply chroma, never add:
safe for tokens near the edge */
background: oklch(
from var(--brand) l calc(c / 4) h);
Published