oklch() and oklab() — Modern Color Spaces
When to Use
Use
oklchfor design token systems and color palettes — its perceptually uniform lightness means adjustingLgives predictable brightness changes across all hues. Usehexorrgbfor exact brand color matching.
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 a perceptually uniform scale. In HSL, 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. Prefer oklab for gradient interpolation.
Browser support: Chrome 111, Firefox 113, Safari 15.4. Widely available since May 2023. Safe to use.
Common Mistakes
- Wrong: Assuming OKLCH hue 0° is red → Right: OKLCH hue 0° is closer to magenta/pink; ~41° is red, ~250° is blue (different from HSL where 0°=red, 240°=blue)
- Wrong: Setting
Cabove ~0.37 expecting full color → Right: Values above ~0.37 may be clamped on sRGB screens; wide gamut is only fully visible on P3 displays - Wrong: Using
oklchfor exact brand color matching → Right: If a brand color is#1d6efa, convert it once; the resulting decimal values are fragile to hand-edit
See Also
- color-mix()
- Relative Color Syntax
- Reference: MDN oklch()