Color Theory

OKLCH Perceptual Color

A color model designed to match human perception. Same Lightness, same Chroma — every hue behaves consistently. Smoother gradients, more predictable palettes, and a native CSS syntax supported across all modern browsers.

3
Axes — L · C · H
P3
Native Wide Gamut
92%
Global browser support
The 3 Axes

Lightness · Chroma · Hue

Every OKLCH color is defined by three independent values. Unlike HSL, each axis controls exactly one perceptual property without affecting the others.

L
Lightness
0 – 1  ·  0% – 100%

Controls perceived brightness. 0 is absolute black, 1 is white. Perceptually uniform: stepping from 0.4 to 0.5 produces the same visual change as from 0.7 to 0.8.

C
Chroma
0 – ~0.37  ·  depende del gamut

Color intensity — similar to saturation but in absolute perceptual units. 0 always produces a neutral gray. The maximum varies by hue and available gamut.

H
Hue
0° – 360°

The hue angle in degrees. 0° red, 120° yellow-green, 180° cyan, 264° blue, 300° magenta. Changing only H never affects perceived brightness.

Interactive

Color Picker

Adjust the three axes and observe how each one modifies the color in a predictable, independent way.

L — Lightness 0.650
C — Chroma 0.180
H — Hue 264.0°
oklch oklch(0.650 0.180 264.0)
hex #—
gamut
Visual Perception

Perceptual Uniformity

With the same Lightness value in OKLCH, every hue is perceived at the same brightness level. In HSL, yellow always appears lighter than blue.

OKLCH   L=0.65 · C=0.18 · H=0°…315°
HSL      S=65% · L=65% · H=0°…315°
Why does this matter?
When building a palette with OKLCH, all colors at the same scale step (e.g. 500) carry the same visual weight. A red button and a blue button will look equally prominent without any manual per-hue adjustments.
Color Interpolation

Gradients

The interpolation space determines which colors are generated between stops. OKLCH preserves saturation; other methods produce muddy midpoints or unwanted rainbows.

in oklch
Smooth transition with preserved saturation. No dead zone in the middle.
recommended
in hsl
Travels the color wheel. Produces unwanted greens and cyans in between.
avoid
srgb (default)
Linear sRGB interpolation. The center becomes muted and dark.
contextual
/* ✓ OKLCH — saturation preserved throughout */
background: linear-gradient(to right in oklch,
  oklch(0.65 0.22 45),
  oklch(0.65 0.22 264)
);

/* También con color-mix */
color: color-mix(in oklch, red 60%, blue);
Design System

Our Palette in OKLCH

The system colors expressed in OKLCH. Hover each step to see its exact value. The 500 level is the central chromatic reference for each family.

Reference

CSS Syntax

OKLCH is a native CSS function. No preprocessor or external library required.

/* Basic value */
color: oklch(0.7 0.15 220);

/* With percentages */
color: oklch(70% 0.15 220);

/* With alpha */
color: oklch(0.7 0.15 220 / 50%);
/* color-mix in OKLCH */
color: color-mix(
  in oklch,
  oklch(0.7 0.2 145) 40%,
  oklch(0.7 0.2 264)
);

/* Gradient with interpolation */
background:
  linear-gradient(in oklch,
    oklch(0.8 0.1 145),
    oklch(0.8 0.1 264));
/* Dynamic custom properties */
:root {
  --hue: 264;
  --brand: oklch(
    0.65 0.2 var(--hue));
}

/* Hover — only lower Lightness */
:hover { background:
  oklch(from var(--brand)
    calc(l - 0.08) c h);
}
/* Robust fallback pattern */
color: #127ae6;         /* sRGB fallback */
color: oklch(0.52 0.19 254);

/* Or with @supports */
@supports (
  color: oklch(1 0 0)
) {
  color: oklch(0.52 0.19 254);
}
Compatibility

Browser Support

OKLCH is supported in all modern browsers since 2023. Over 92% of users have native support today.

Chrome 111+
Safari 15.4+
Firefox 113+
Edge 111+
Production fallback
Always write a hex or rgb value as a fallback before the oklch() value. Modern browsers will use oklch(); older ones fall back gracefully. In most cases, @supports is not needed.
Automatic Wide Gamut
On screens with Display-P3 support (iPhone, MacBook, modern monitors), OKLCH can render colors outside the sRGB range automatically. No special declaration is needed — the browser handles it natively.