Why OKLCH? The problem with RGB and HSL
RGB is the native color model of display hardware — red, green, and blue channels each from 0 to 255. It is precise, widely understood, and directly maps to screen pixels. But it has no relationship to human color perception: (0, 255, 0) pure green appears dramatically lighter than (0, 0, 255) pure blue despite both being 'fully saturated' colors. HSL (hue, saturation, lightness) was designed to be more intuitive than RGB, and it is — but its lightness axis is not perceptually uniform. The result is that HSL-based color scales (where you vary lightness while keeping hue and saturation constant) produce tonal ramps where some steps appear to jump while others barely change. OKLCH solves this by working in a color space where the L axis is calibrated to human perception — any color at L=0.6 will appear equally light to the eye regardless of its hue or chroma. This is the foundational property that makes OKLCH so valuable for system design.
Understanding the three OKLCH axes
L (Lightness): Ranges from 0 to 1. L=0 is absolute black, L=1 is absolute white. Unlike HSL, this lightness is perceptually calibrated — perceived brightness changes uniformly as L changes. For practical use: L=0.1-0.2 is very dark, useful for near-black surface backgrounds. L=0.3-0.5 is the range for dark brand colors. L=0.5-0.7 is midtones where most colors live. L=0.7-0.9 is light tints. L=0.9-1.0 is near-white. C (Chroma): Ranges from 0 to approximately 0.4, depending on hue and lightness. C=0 is achromatic (gray). C=0.05 is a very subtle tint. C=0.1-0.15 is clearly colorful. C=0.2+ is vivid. Not all L/C combinations are in-gamut for sRGB displays — very high chroma values especially in the blue-purple range may need to be clamped or gamut-mapped. H (Hue): A 0-360° hue angle. Key landmarks: 0°=pink/red, 30°=orange-red, 60°=orange, 90°=yellow, 120°=yellow-green, 150°=green, 180°=aqua, 210°=cyan, 240°=sky blue, 270°=blue, 300°=blue-violet, 330°=magenta.
Generating color scales in OKLCH
The primary practical application of OKLCH for developers is generating tonal color scales — the 50-to-950 scales used in design systems like Tailwind, Radix, and Material. The OKLCH approach: choose a base color, identify its OKLCH values, then vary only L while keeping C and H (approximately) constant to generate the scale steps. For a 11-step scale (50, 100, 200, 300, 400, 500, 600, 700, 800, 900, 950), choose L values that produce perceptually even steps: a linear distribution from L=0.97 (50 — near white) to L=0.15 (950 — near black) generally works well as a starting point. The result is a scale where each step looks equally spaced to the eye, which is the property most often missing from manually curated scales. For chroma: it is common to slightly reduce chroma at the lightest and darkest ends of the scale (the tints and shades) and peak chroma at 500 (the base color). This follows the natural behavior of pigment-based colors and avoids the slightly plastic look of very high-chroma light tints.
OKLCH in CSS: syntax and browser support
OKLCH is fully supported in CSS as of 2023 in all major browsers. The syntax: `oklch(L C H)` or `oklch(L C H / alpha)` where L is 0-1 or 0%-100%, C is 0-0.4 (unitless) or 0%-100% (where 100% = 0.4), and H is an angle in degrees. Examples: `oklch(0.7 0.15 250)` is a medium-light blue. `oklch(0.3 0.1 30)` is a dark warm brown. `oklch(0.95 0.02 90)` is a very light warm cream. For gradients: use `background: linear-gradient(in oklch, oklch(0.5 0.2 30), oklch(0.5 0.2 270))` to get a vivid gradient that maintains saturation through the midpoint. The `color-mix()` function also accepts OKLCH: `color-mix(in oklch, #FF6600 60%, #0066FF 40%)` produces the perceptually correct mix. For TypeScript utilities, a complete OKLCH implementation (sRGB ↔ OKLCH conversion) is available via the oklab and culori JavaScript libraries, or can be implemented from Björn Ottosson's reference code (approximately 50 lines of math).
Practical OKLCH for accessible color systems
WCAG contrast ratios are based on relative luminance, which correlates strongly with OKLCH's L axis (with some deviation). Using OKLCH to build accessible color pairs is more predictable than using HSL or RGB. The general guideline: for WCAG AA normal text (contrast ratio ≥ 4.5:1), a combination of L=0.9+ background with L=0.4 or lower text color reliably passes. For large text and UI components (contrast ratio ≥ 3:1), L=0.85+ background with L=0.5 or lower passes in most cases. The perceptual uniformity of OKLCH means that if you verify contrast for one hue, a color with the same L value in a different hue will have similar contrast behavior — unlike HSL where identical lightness values produce dramatically different actual luminance. This makes OKLCH a much more reliable tool for designing accessible color systems across a range of hues. Use the OKLCH L axis to quickly identify the lightness threshold that gives you the required contrast, then choose any hue at that lightness level — the contrast relationship will hold.