# OKLCH explained: perceptual colour for designers

[Canonical HTML page](https://gradiently.design/guide/oklch-explained)

HSL promised readable colour and nearly delivered. OKLCH keeps the readable part and fixes the lie about lightness, which is why design systems are moving to it.

## The short version

- OKLCH describes a colour with three values: perceptual lightness (L), chroma or colourfulness (C) and hue angle (H).
- Unlike HSL, OKLCH lightness matches how bright colours look to people, so two colours with the same L have similar contrast against white.
- In CSS it is written oklch(60% 0.2 293), with optional alpha after a slash, and all current major browsers support it.
- Chroma has no fixed maximum: how much colour is possible depends on the lightness, the hue and the display, and colours beyond the screen's range are mapped back into it.
- Interpolating gradients in OKLCH or OKLab avoids the grey, muddy middle that sRGB blends produce between distant hues.

**OKLCH** is a way of writing colour as lightness, chroma and hue, where lightness is measured the way human eyes perceive it. In CSS, `oklch(60% 0.2 293)` is a violet that looks 60% of the way from black to white, with strong colour, at a hue angle of 293 degrees. The practical win for designers is simple: change the hue and keep L the same, and the new colour looks just as light. HSL cannot promise that, and it is the reason OKLCH has become the default in newer design systems, including Tailwind's colour palette.

## Lightness, chroma and hue

| Letter | Name | Range | What it controls |
| --- | --- | --- | --- |
| L | Lightness | 0% to 100% (or 0 to 1) | How light the colour looks, as eyes judge it |
| C | Chroma | 0 upwards, rarely above 0.37 | How much colour: 0 is grey, higher is more vivid |
| H | Hue | 0 to 360 degrees | Which colour: roughly 30 red, 110 yellow, 140 green, 265 blue |
| / A | Alpha | 0 to 1, or 0% to 100% | Opacity, optional |

Hue angles in OKLCH do not line up with HSL's. Pure blue sits near 264 here, not 240.

**Lightness** is the star. It comes from OKLab, a colour space published in 2020 that was built to predict perceived lightness, colourfulness and hue more evenly than older models. **Chroma** replaces saturation: rather than a percentage of some maximum, it is an absolute amount of colour, so a chroma of 0.1 means the same visual intensity whatever the hue. **Hue** is still an angle, but the angles are spaced so that a 30 degree step looks like a similar change all the way round.

## OKLCH vs HSL: the same lightness, side by side

Take six hues and hold lightness and chroma fixed at `oklch(65% 0.11 H)`. The swatches below look like one family, and their contrast against white stays between 3.1:1 and 3.4:1. Do the same in [HSL](https://gradiently.design/guide/hsl-colors) at 50% lightness and contrast against white swings from about 1.07:1 for yellow to 8.6:1 for blue.

- H 30 #c97466: #c97466
- H 90 #a98c35: #a98c35
- H 150 #5aa26b: #5aa26b
- H 210 #11a1b4: #11a1b4
- H 270 #758bd3: #758bd3
- H 330 #b576af: #b576af

oklch(65% 0.11 H) at six hues. Equal lightness, equal chroma, and they genuinely look it.

That evenness is what makes OKLCH useful for real work. A set of status colours, chart series or category tags can share one L and C and differ only in hue, and none of them shouts louder than the others. If you then need a colour blind safe set, you vary L as well, which is covered in [colour blind friendly palettes](https://gradiently.design/guide/color-blindness-design).

## How to write OKLCH in CSS

```css
:root {
  /* lightness as a percentage or a number */
  --violet: oklch(60% 0.2 293);
  --violet-same: oklch(0.6 0.2 293);

  /* with transparency */
  --violet-soft: oklch(60% 0.2 293 / 0.4);

  /* grey: chroma 0, hue ignored */
  --grey: oklch(60% 0 0);
}

/* a fallback for very old browsers comes first */
.button {
  background: #8860ea;
  background: oklch(60% 0.2 293);
}
```

oklch(60% 0.2 293) is close to #8860ea in sRGB. Current versions of Chrome, Edge, Firefox and Safari all support oklch().

Browser support is broad, and you can confirm the detail on [caniuse](https://caniuse.com/mdn-css_types_color_oklch). To explore values visually, [oklch.com](https://oklch.com) is a picker that shows which combinations a normal screen can display. To convert an existing brand hex, paste it into that picker or into your browser devtools colour panel, which can display any colour in OKLCH.

## Building a scale with OKLCH

To make a tint and shade scale, step lightness evenly and let chroma rise towards the middle and fall towards the ends. Very light and very dark colours physically cannot hold much colour, so if you keep chroma high at the extremes the browser has to clip them. Here is a violet scale built that way.

- L 97 C .015: #f5f3ff
- L 90 C .05: #dfd9fd
- L 80 C .10: #c0b2f9
- L 70 C .17: #a486fd
- L 60 C .22: #8a5af4
- L 50 C .22: #6e37d2
- L 40 C .18: #50249d
- L 30 C .12: #331b63
- L 20 C .07: #180d32

Hue 293 throughout. Each step is a similar visual jump, which HSL scales rarely manage.

Because L tracks perceived lightness, you can make rough contrast decisions from the numbers alone. In this scale, white text passes 4.5:1 from L 50 downwards, and black text passes from L 60 upwards. Always confirm with a [contrast checker](https://gradiently.design/guide/color-contrast-accessibility), but you will rarely be surprised. Turning a scale like this into named tokens is covered in [design tokens](https://gradiently.design/guide/design-tokens).

## Gamut: when a colour does not exist on screen

OKLCH can describe colours no screen can show. Most monitors display sRGB; many recent phones and laptops display the wider Display P3. Push chroma high enough and you leave both. When that happens the browser maps the colour back to the nearest one the display can show, so nothing breaks, but you may not get what you typed.

### Avoid

- High chroma at very light or very dark L
- Copying P3 values into a brand guide meant for print
- Assuming a vivid OKLCH colour looks the same on every screen
- Using chroma above about 0.2 for large background areas

### Do

- Check values in a picker that marks the sRGB edge
- Keep a hex fallback for brand colours
- Lower chroma towards the ends of a scale
- Save the most vivid colours for small accents

## OKLCH gradients

Gradients are where perceptual colour pays off most visibly. A plain CSS gradient blends in sRGB, which dips into grey between distant hues. Modern CSS lets you choose the space to blend in, and OKLab or OKLCH keeps the middle bright and clean.

- Blended in sRGB: grey middle: `linear-gradient(90deg in srgb, #2563eb, #facc15)`
- Blended in OKLab: clean: `linear-gradient(90deg in oklab, #2563eb, #facc15)`
- Blended in OKLCH: through green: `linear-gradient(90deg in oklch, #2563eb, #facc15)`

The same two colours three ways. OKLCH travels round the hue wheel, so it can pass through hues neither end contains.

OKLab blends in a straight line and suits most two colour gradients. OKLCH rotates hue, which is lovely for sunsets and rainbows but can surprise you. The full technique, including the `shorter hue` and `longer hue` keywords, is in [CSS gradients in OKLCH](https://gradiently.design/guide/css-gradient-oklch), and the theory behind it in [gradient interpolation](https://gradiently.design/guide/gradient-interpolation).

Gradiently's Marks are rendered live rather than written as CSS, and each carries its own palette: auto ink picks light or dark type from that palette for every line, so the words read without you checking numbers. If you would rather start from a finished living background than a value in a picker, browse the Market by colour words.

## FAQ

### What is OKLCH?

OKLCH is a colour format based on the OKLab colour space. It describes colours by perceptual lightness, chroma and hue, so equal values look equally light and vivid.

### Is OKLCH better than HSL?

For building palettes, scales and gradients, yes, because its lightness matches what eyes see. HSL is still fine for quick hand edits.

### Can I use oklch() in CSS today?

Yes. Current versions of Chrome, Edge, Firefox and Safari support it. Put a hex fallback first if you must support very old browsers.

### What is the maximum chroma in OKLCH?

There is no fixed maximum. The possible chroma depends on lightness, hue and the display; in sRGB most hues top out well below 0.37.

### How do I convert hex to OKLCH?

Paste the hex into an OKLCH picker such as oklch.com, or into your browser devtools colour panel, which can show the same colour in OKLCH.
