color-oklch-palettes
Color: OKLCH Perceptual Palettes
When to use this
- You need a color ramp where each step looks evenly spaced in lightness to the human eye.
- You are computing contrast ratios and need them to be reliable, not a guess from hex values.
- You are building a dark mode palette and the naive "invert the ramp" approach looks wrong.
- You need to understand chroma limits per hue so saturated colors do not clip to gamut boundaries.
- Do NOT use this when you need the DTCG token file format or Style Dictionary pipeline; use
design-tokens-dtcginstead.
Mental model
OKLCH is a cylindrical color space with three axes: L (perceptual lightness, 0-1), C (chroma / saturation, 0 to ~0.4), H (hue angle, 0-360). "Perceptual" means equal numeric steps in L produce equal visual steps in lightness. sRGB, HSL, and even LCH (the older CIELab-based one) do not have this property -- in HSL, stepping from hsl(60,100%,50%) to hsl(240,100%,50%) changes perceived lightness dramatically even though L stays at 50%.
OKLCH solves three problems at once. First, ramp generation: you hold C and H constant and step L linearly. The resulting ramp looks uniform. Second, accessible contrast: APCA (the next-gen contrast algorithm) and WCAG 3.0 both operate on perceptual lightness, so computing contrast in OKLCH is closer to ground truth. Third, hue consistency: rotating H at constant L and C does not cause the wild lightness jumps you get in HSL.
Chroma has a hard limit that varies by hue and lightness. At any given L and H, there is a maximum C before the color falls outside the sRGB gamut. Blues can sustain higher chroma at low lightness; yellows peak in chroma at high lightness. Ignoring this produces colors that get silently clamped by the browser, breaking your carefully computed ramp.
Dark mode inversion is not symmetric. In light mode, your surface is high-L and your text is low-L. Flipping them does not work because chroma response is asymmetric across the lightness axis: a blue at L=0.45 C=0.2 has no equivalent at L=0.85 C=0.2 (it clips). You must reduce chroma as you push accent colors into higher lightness for dark backgrounds.