Skip to content
ColorArchive
Developer Tools Guide
Search intent: OKLCH color space, oklch css, perceptually uniform color, oklch vs hsl, oklch color picker, oklch gradient, oklch color system

OKLCH Color Space: The Developer's Guide to Perceptually Uniform Color

OKLCH is a perceptually uniform color space designed for digital design and CSS that solves several fundamental problems with sRGB, HSL, and older color models. Developed by Björn Ottosson in 2020, OKLCH builds on OKLab (an improved version of the CIELAB color space) to provide three human-perceptible axes — Lightness, Chroma, and Hue — where equal numerical distances correspond to equal perceived color differences. For designers and developers building color systems, OKLCH offers unprecedented control over color ramps, gradients, and palette generation.

Developer ToolsColor Theory
Key points
The key insight of OKLCH: L (lightness) is perceptually uniform. In HSL, a color at 50% lightness may appear much darker or lighter than another color at 50% lightness — compare HSL(60, 100%, 50%) (vivid yellow) with HSL(240, 100%, 50%) (vivid blue). The yellow appears significantly lighter to the eye despite identical HSL lightness values. In OKLCH, oklch(0.7, -, -) yellow and oklch(0.7, -, -) blue will appear equally light to the human eye regardless of hue. This makes OKLCH dramatically better for generating color scales, gradients, and accessible color combinations.
CSS now natively supports OKLCH: `oklch(L C H)` is valid in all modern browsers (Chrome 111+, Firefox 113+, Safari 15.4+). The L axis runs from 0 (black) to 1 (white). The C (chroma) axis runs from 0 (gray) to approximately 0.4 (maximum saturation, varies by hue). The H axis is a hue angle from 0° to 360°. Unlike HSL's saturation, OKLCH chroma is absolute — a chroma of 0.2 means the same amount of colorfulness regardless of lightness, which makes it much more predictable when building tonal scales.
OKLCH gradients look better than RGB or HSL gradients. Gradients computed in RGB can produce muddy brown or gray midpoints when interpolating between complementary colors. Gradients in HSL can produce hue arcs (unexpected color stops in the middle of what should be a two-color blend). OKLCH interpolation maintains vivid, clean midpoints between any two colors because the perceptual path through OKLCH space is shorter and avoids the desaturated region at the center of the color gamut. This is why CSS `color-mix(in oklch, ...)` is the recommended approach for high-quality color interpolation in modern CSS.

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.

Practical next step

Move from the guide into a concrete palette lane

Guides explain the use case. Collections prove the taste. Packs handle the export and implementation layer.

Related guides