WebCraft

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.

CSS
: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