The OKLCH Adoption Guide
HSL was a brilliant hack for 1970s hardware. In 2024, continuing to use HSL for programmatic color generation guarantees accessibility failures. Enter OKLCH.
The Problem with HSL
HSL (Hue, Saturation, Lightness) is a cylinder mapping of the RGB space. It is mathematically simple but perceptually inaccurate.
If you build a button component and set the text color to white, and the background to hsl(X, 100%, 50%), the contrast ratio will wildly swing between passing and failing depending entirely on the Hue (X). A yellow hue at 50% lightness is nearly white (failing contrast). A blue hue at 50% lightness is quite dark (passing contrast).
OKLCH: Perceptual Uniformity
OKLCH stands for Lightness, Chroma, and Hue (using the Oklab color space).
- L (Lightness): 0% (Black) to 100% (White). This maps directly to human perception.
- C (Chroma): 0 (Grayscale) to theoretical infinity (though monitors max out around 0.3-0.4 depending on gamut).
- H (Hue): 0 to 360 degrees.
/* A perceptually uniform color scale */
:root {
--hue-brand: 250; /* Blue */
--brand-100: oklch(95% 0.05 var(--hue-brand));
--brand-500: oklch(65% 0.2 var(--hue-brand));
--brand-900: oklch(25% 0.1 var(--hue-brand));
}
If you change --hue-brand from 250 (Blue) to 90 (Yellow), the perceived brightness of the buttons will not change. The contrast ratio against white text remains stable. This is the holy grail of theming.
Browser Support
As of late 2023, OKLCH is supported in all major browser engines (Chrome 111+, Safari 15.4+, Firefox 113+). Global support is hovering around 90%. For critical systems, providing an RGB/Hex fallback is still recommended.