HSL lightness is not what you think

Every swatch below has identical L=50% in HSL. They should look equally bright — but your eye clearly sees different brightness levels. Yellow looks near-white. Blue looks near-black. HSL's lightness is mathematical, not perceptual.

HSL — hsl(H, 90%, 50%)

OKLCH — oklch(0.65, 0.20, H)

The OKLCH row uses L=0.65 for all — they look genuinely similar in brightness because OKLCH is calibrated to human vision.

Drag the hue — watch what happens

Left half is HSL, right half is OKLCH. Both use the same lightness value. As you move through hues, notice that HSL brightness jumps while OKLCH stays stable. This is the perceptual uniformity difference in real time.

hsl(260, 80%, 55%)
oklch(0.55 0.20 260)
Hue H 260°
Lightness 55%
HSL
hsl(260, 80%, 55%)
OKLCH equivalent
oklch(0.55 0.20 260)

Lightness scale: equal steps, unequal results

Both strips go from dark to light in 9 equal mathematical steps. In HSL the jumps look uneven — the middle steps cluster. In OKLCH each step looks like the same visual distance. Pick a hue to try it on.

Hue H 30°

HSL — L steps: 10%, 20%, 30%... 90%

10%20%30%40%50%60%70%80%90%

OKLCH — L steps: 0.10, 0.20, 0.30... 0.90

0.100.200.300.400.500.600.700.800.90
Why this matters for design systems: When you build a color scale (like Tailwind's 100–900 shades), you want each step to look like the same visual jump. HSL gives you uneven jumps. OKLCH gives you genuinely uniform ones. This is why Tailwind v4 switched to OKLCH for its entire color palette.

Gradients: HSL goes muddy in the middle

Interpolating from blue to yellow in HSL passes through a desaturated, gray-ish zone. In OKLCH the path stays vivid the whole way. This directly affects CSS gradients and color transitions.

HSL — linear-gradient(to right, hsl(240,80%,50%), hsl(60,80%,50%))
Notice the dull, desaturated middle — the gradient passes through hue 150° (green) and loses vividness.
OKLCH — linear-gradient(in oklch to right, oklch(0.45 0.22 260), oklch(0.78 0.18 90))
Stays vivid throughout. OKLCH interpolates through perceptual space, not raw hue angle.

The syntax, side by side

OKLCH reads like HSL — three parameters, same mental model — but the numbers actually match what your eyes see.

Parameter In HSL In OKLCH What it controls
Lightness L 0%–100% (not perceptual) 0–1 or 0%–100% (perceptual) How bright the color looks to a human eye
Saturation / Chroma C 0%–100% 0–0.37 approx How vivid vs gray — OKLCH C can exceed sRGB into P3 gamut
Hue H 0°–360° 0°–360° The color angle — blue ~260°, red ~25°, green ~145°