Bhinish Dhiman· updated 3 October 2026
OKLCH for designers — why it replaced HSL
In HSL, 50% lightness looks very different for yellow than for blue, so a ramp built on even HSL steps comes out uneven. OKLCH is perceptually uniform — equal lightness steps look equal to the eye — which makes it the correct space for ramps, dark-mode variants and contrast fixes.
If you have ever built a colour ramp by stepping HSL lightness evenly and found the middle looked wrong, you have met the reason OKLCH exists.
What is wrong with HSL
HSL is convenient. Hue as an angle, saturation and lightness as percentages — easy to reason about, easy to adjust by hand.
The problem is that its lightness axis does not correspond to perceived lightness. hsl(60 100% 50%) is a vivid yellow. hsl(240 100% 50%) is a deep blue. Both claim 50% lightness. Put them side by side and the yellow is dramatically brighter — the measured relative luminance is 0.928 against 0.072, about thirteen times apart.
This is not a rounding error. It is a consequence of HSL being a straightforward mathematical transform of RGB, with no model of human vision in it at all. Our eyes are far more sensitive to green wavelengths than to blue, and HSL does not know that.
The practical damage:
- A ramp built on even HSL steps looks uneven, bunching in some regions and jumping in others
- Two colours at the same HSL lightness have wildly different contrast against the same background
- Adjusting saturation shifts apparent lightness as a side effect
What OKLCH does differently
OKLCH is built on the Oklab colour space, designed specifically so that numerical distance matches perceived distance.
Three components:
- L — lightness, 0% to 100%, perceptually uniform
- C — chroma, roughly saturation, starting at 0 with no fixed upper bound
- H — hue, 0 to 360 degrees
The important property: equal steps in L look like equal steps. oklch(50% 0.2 60) and oklch(50% 0.2 250) genuinely read as the same lightness, one yellow-orange and one blue.
That makes the three components independent in the way designers already assume they are. You can change lightness without the colour appearing to shift hue, and change hue without the colour appearing to get lighter.
Why this matters for contrast
Contrast is driven almost entirely by lightness. Hue barely affects it and saturation affects it hardly at all.
In OKLCH, that means there is exactly one knob to turn. Hold H and C, move L, and you change the contrast while keeping the colour recognisably itself. In HSL the same move would shift the apparent colour, because HSL’s lightness is entangled with everything else.
This is what makes “keep the brand colour, fix the contrast” a tractable problem rather than a negotiation. Your brand lives in hue; the measurement lives in lightness; OKLCH keeps them separate.
Building a ramp
The standard approach is to hold hue, step lightness evenly, and taper chroma at both ends — because very light and very dark colours cannot sustain high saturation without falling outside the displayable range.
--blue-100: oklch(95% 0.03 255);
--blue-300: oklch(82% 0.09 255);
--blue-500: oklch(62% 0.16 255);
--blue-700: oklch(48% 0.14 255);
--blue-900: oklch(30% 0.08 255);
One hue, even lightness steps, chroma peaking in the middle. The result looks like a coherent family, which is exactly what an evenly-stepped HSL ramp fails to deliver.
The gamut trap
OKLCH can describe colours your screen cannot show. oklch(70% 0.4 150) is a perfectly valid coordinate and far outside sRGB.
When that happens the browser clips, and clipping is not graceful — it can shift hue noticeably, so the colour you get is not the one you specified. Any tool doing OKLCH maths needs to reduce chroma until the colour fits, rather than letting it clip. If you are hand-authoring, keep chroma below about 0.24 for sRGB safety, or check in a gamut-aware tool.
Browser support
OKLCH has been supported in all major browsers since 2023 and is Baseline widely available. You can write it directly in CSS with no fallback for most audiences:
color: oklch(62% 0.16 255);
Tailwind CSS v4 uses OKLCH for its default palette, which is a reasonable signal about where the ecosystem has landed.
When HSL is still fine
For a quick one-off tweak on a single colour, HSL is perfectly serviceable and the mental model is familiar.
The moment you are generating a system — a ramp, a set of semantic tokens, light and dark variants of the same brand colour — the uniformity matters, and HSL will fight you the whole way.
Our contrast checker searches in OKLCH for exactly this reason: it can hold your hue and chroma fixed and move only the lightness, which is how it finds the nearest passing colour that still looks like yours.