Dev Hub Solutions

Product studio

Get in touch
5 min readdesign / color / frontend

OKLCH is the design system color space for 2026

OKLCH ships in every modern browser, fixes the perceptual problems that HSL has, and makes palette generation and accessibility tractable. Here's why to commit.

Pick a color in HSL with 50% lightness. Now pick another color with 50% lightness at a different hue. They will look different brightnesses to your eyes. Your designers know this. Your accessibility audits know this. The browser does what you asked, but what you asked was the wrong question.

OKLCH fixes this. In 2026, it's the right default for new design systems.

What OKLCH is

OKLCH is a perceptually uniform color space, polar form. Three components:

  • L (Lightness): 0% (black) to 100% (white). A given L value looks like the same brightness across every hue.
  • C (Chroma): 0 (grey) to ~0.4 (most saturated representable). Like saturation, but perceptually scaled.
  • H (Hue): 0-360°. Like HSL's hue, but the perceptual distance between hues is more even.

Written: oklch(60% 0.18 250) — 60% lightness, 0.18 chroma, hue 250°.

Behind it is OKLab, a 2020 color space designed by Björn Ottosson specifically to fix the problems with previous "uniform" color spaces (CIELAB had its own issues with blue-vs-yellow distance). OKLCH is the polar form of OKLab — more intuitive for design work where you think in terms of hue.

Why HSL fails

HSL was designed in the 1970s as a more intuitive way to talk about RGB. Hue, saturation, lightness — easy to reason about. But the perceptual problem is in the math: HSL's "lightness" is a mathematical average of RGB channels, not a perceptual model. Yellow at 50% L looks much brighter than blue at 50% L because your eyes are more sensitive to yellow wavelengths.

This breaks three things:

Palettes. Generate a triadic palette in HSL — three hues at equal saturation and lightness — and you get one washed-out color and two vibrant ones. Designers manually re-balance. The math didn't help.

Accessibility. WCAG contrast ratios are luminance-based, not L-based. An HSL palette with consistent L can have wildly different contrast ratios against the same background. OKLCH doesn't fix this exactly (you still need to compute proper contrast), but it's a closer match — a uniform L in OKLCH means a closer-to-uniform contrast.

Theme variants. "Slightly darker" via HSL produces different perceptual shifts across hues. OKLCH's L is consistent — L - 10% darkens every hue by the same perceived amount.

Browser support

oklch() ships in:

  • Safari 15.4+ (March 2022)
  • Firefox 113+ (May 2023)
  • Chrome 111+ (March 2023)
  • Edge 111+ (March 2023)

By mid-2026, all evergreen browsers support it. The remaining lag is around fallbacks for some embedded clients (older email clients, ancient corporate browsers).

How to actually adopt

The migration looks like this:

  1. Author tokens in OKLCH. Store oklch(60% 0.18 250) in your CSS custom properties or design token JSON. Use OKLCH as the source of truth.

  2. Generate palette variants by manipulating L. A "hover" state is the base color with L + 5%. A "pressed" state is L - 5%. A muted variant is the base hue with C - 0.1. Because L and C are perceptual, the variants look right across every hue.

  3. Ship sRGB fallbacks for legacy targets. For email or older browsers, generate the equivalent hex/RGB at build time. CSS Color Level 5's @supports and the fallback syntax handles this cleanly:

.button {
  background: #3b82f6;
  background: oklch(60.4% 0.21 254);
}

Modern browsers use the second declaration; older ones use the first.

Palette generation in OKLCH

In HSL, generating a 5-color palette at the same brightness requires manual re-balancing. In OKLCH, you pick a target L and C, then rotate H:

:root {
  --color-1: oklch(60% 0.18 30);   /* warm red */
  --color-2: oklch(60% 0.18 100);  /* yellow-green */
  --color-3: oklch(60% 0.18 170);  /* teal */
  --color-4: oklch(60% 0.18 240);  /* blue */
  --color-5: oklch(60% 0.18 310);  /* magenta */
}

Five colors at the same L and C, evenly spaced in hue. They look balanced because the perceptual distance between them is consistent. The same trick in HSL produces visible imbalances.

OKLCH for accessibility

OKLCH doesn't directly compute WCAG contrast — you still need to convert to relative luminance for that. But OKLCH-derived palettes are closer to WCAG-compliant by default because L is a much better proxy for luminance than HSL's L is.

Practically: a button with color: oklch(20% ...) on background: oklch(95% ...) will pass WCAG AA contrast against most hue choices. The same recipe in HSL fails for some hues.

When OKLCH is wrong

  • Targeting display-P3 wide gamut. OKLCH can describe colors outside sRGB. If you author in OKLCH and your CSS pipeline assumes sRGB, you'll get unintended clipping. CSS Color Level 4's color-interpolation hints help but require deliberate setup.
  • Legacy embedded clients. Some email clients still don't render oklch(). Use fallbacks per above.
  • Teams without designer buy-in. OKLCH is more abstract than HSL — designers used to "60% saturation" need a moment to internalize "0.15 chroma". Worth the investment for a long-lived design system; not worth the friction for a one-off.

Tools

Our color picker shows HEX, RGB, HSL, and OKLCH side by side for any color you pick. The HEX → OKLCH converter takes a HEX and produces the OKLCH equivalent — useful for porting an existing palette.

For palette generation, our picker generates complementary, analogous, and triadic palettes directly in OKLCH math so the output is balanced by default.