oklch() and oklab() — Modern Color Spaces
When to Use
When defining design tokens, building color palettes, or generating accessible color variations. OKLCH produces perceptually uniform lightness across hues — adjusting
Lgives predictable brightness changes regardless of hue. HSL does not.
Decision
| If you need... | Use... | Why |
|---|---|---|
| Design token system with consistent lightness | oklch |
Perceptually uniform — same L looks equally bright across hues |
| Accessible dark/light variants from one base | oklch + adjust L |
Predictable contrast relationship |
| Wide gamut (P3) colors | oklch |
Naturally expresses values beyond sRGB |
| An exact hex/brand color | hex or rgb |
OKLCH is for token-driven palettes, not color matching |
| Smooth color interpolation in gradients | oklab or oklch |
More perceptually even gradients than RGB or HSL |
Pattern
Token system using OKLCH — one base color generates a full scale:
:root {
/* Brand blue — l=lightness(0-1), c=chroma(0-0.4), h=hue(0-360) */
--brand-50: oklch(95% 0.05 250);
--brand-100: oklch(88% 0.09 250);
--brand-400: oklch(65% 0.18 250);
--brand-500: oklch(55% 0.18 250); /* base */
--brand-600: oklch(45% 0.18 250);
--brand-900: oklch(25% 0.12 250);
}
The same c (chroma) and h (hue) values held constant while adjusting L guarantees the scale is perceptually uniform. In HSL, doing this produces wildly inconsistent apparent brightness.
Parameter reference:
| Parameter | Range | What it controls |
|---|---|---|
L |
0%–100% (or 0–1) | Perceived lightness — 0=black, 100=white |
C |
0–0.4 (practical max) | Chroma / color intensity — 0=gray |
H |
0–360deg | Hue angle (0°≈pink/red, 120°≈green, 250°≈blue) |
oklab vs oklch: oklab uses Cartesian coordinates (a, b axes); oklch uses polar coordinates (C, H). Prefer oklch for token definition — hue as a degree angle is more intuitive. Prefer oklab for gradient interpolation.
Browser support: Chrome 111, Firefox 113, Safari 15.4. Widely available since May 2023. Safe to use.
Common Mistakes
- Assuming OKLCH hue 0° is red — it is closer to magenta/pink; hue ~41° is red, ~250° is blue (different from HSL where 0°=red, 240°=blue)
- Setting
Cabove the display gamut — values above ~0.37 may be clamped on sRGB screens; wide gamut is only fully visible on P3 displays - Using
oklchfor color matching — if a brand color is#1d6efa, converting it to OKLCH is fine, but the resulting decimal values are fragile to hand-edit
See Also
- color-mix() → for mixing two colors
- Relative Color Syntax → for deriving variants from a base color
- Reference: MDN oklch()