OKLCH Studio · Guides

OKLCH in CSS: syntax, relative colours, color-mix and fallbacks

Updated 2026-10-17

Using OKLCH in a stylesheet is mostly a matter of learning one function and a few conventions. The function is oklch(), it is part of CSS Color Module Level 4, and it has been shipping in browsers long enough that most projects can use it with a small fallback. This guide covers the syntax, the shortcuts, the two features that make OKLCH especially useful in CSS (relative colours and color-mix()), and how to protect users on older browsers.

The examples use blue-500, the middle blue of Tailwind CSS v4's default palette, written as oklch(0.623 0.214 259.8). The tables show real output computed by this site's colour code, not typed by hand.

The oklch() syntax

The function takes three components and an optional alpha: lightness, chroma, hue, then a slash and the opacity. Components are separated by spaces, not commas. A complete example looks like this:

Basic syntax

.button {
  background: oklch(0.62 0.21 260);
  border-color: oklch(0.62 0.21 260 / 0.4); /* 40% opaque */
  color: oklch(98% 0 0);                    /* near-white, no hue needed */
}

Lightness is a number from 0 to 1 or a percentage from 0% to 100%. Chroma is a non-negative number, or a percentage where 100% corresponds to 0.4 in the specification. Hue is an angle: a plain number is read as degrees, and you can use units such as deg, turn, rad or grad. Alpha is a number from 0 to 1 or a percentage. A value of zero chroma gives a pure grey, and in that case the hue does not matter.

  • oklch(0.7 0.15 30) and oklch(70% 0.15 30deg) are the same colour.
  • oklch(70% 40% 30) uses a percentage for chroma, equal to 0.16.
  • oklch(0.7 0.15 0.5turn) places the hue at 180 degrees.

The none keyword and missing components

CSS Color Level 4 lets you write the keyword none for any component. It means that the component is missing, which is not the same as zero, and its effect shows up when colours are interpolated or when you use relative colour syntax. When a component is missing in one colour of a gradient or mix, the browser takes the other colour's value for that channel, so a grey that has none for hue picks up the hue of the colour it is blended with instead of being pulled toward hue 0.

Using none

/* Hue is carried over from the other colour in the blend */
background: color-mix(in oklch, oklch(0.62 0.21 260), oklch(1 0 none));

In ordinary, non-interpolated use, a missing component behaves like zero. So none mostly matters in color-mix(), gradients and animations, where it prevents greys and whites from adding unwanted hue shifts.

Relative colour syntax

Relative colour syntax lets one colour be derived from another. You write oklch(from <colour> l c h), and inside the function the names l, c and h stand for the channels of the source colour, which you can use as they are, replace, or combine with calc(). It turns a single custom property into a whole family of related colours with no preprocessor. The table starts from blue-500 and shifts only the lightness, so hue and chroma stay put.

Derive tints and shades from one variable

:root {
  --brand: oklch(0.623 0.214 259.8);
}
.card {
  background: oklch(from var(--brand) calc(l + 0.2) c h);
  border-color: oklch(from var(--brand) calc(l - 0.1) c h);
  color: oklch(from var(--brand) 0.3 c h);   /* fixed lightness, same hue and chroma */
}
oklch(from blue-500 …) with the lightness shifted, hue and chroma kept
Relative colour channelsResultHexInside sRGB
calc(l + 0.2) c hoklch(0.823 0.214 259.8)#6CC1FFNo (hex is mapped)
calc(l + 0.1) c hoklch(0.723 0.214 259.8)#4CA0FFNo (hex is mapped)
l c hoklch(0.623 0.214 259.8)#2B7FFFNo (hex is mapped)
calc(l - 0.1) c hoklch(0.523 0.214 259.8)#005EE2No (hex is mapped)
calc(l - 0.2) c hoklch(0.423 0.214 259.8)#003DBFNo (hex is mapped)

Note the last column. Tailwind's blue-500 is itself outside the sRGB gamut, and shifting lightness keeps its high chroma, so the rows marked No cannot be shown exactly on a standard display. The browser maps those colours into range, which lowers the chroma a little. On a wide-gamut screen you see more of the intended colour. Relative colour syntax is newer than oklch() itself, so check support for your audience before relying on it without a fallback.

Mixing colours with color-mix()

The color-mix() function blends two colours in a colour space of your choice. Choosing in oklch makes the lightness change steadily, which is usually what you want for tints, shades and hover states. The table compares mixing the same blue with white in OKLCH and in sRGB, with the OKLCH lightness of each result.

Mix with white in OKLCH

.chip {
  background: color-mix(in oklch, var(--brand) 60%, white);
}
blue-500 mixed with white: color-mix in OKLCH versus in sRGB
White addedIn oklchL (oklch)In srgbL (srgb)
25%#65A2FF0.712#609FFF0.704
50%#99C3FF0.809#95BFFF0.799
75%#CBE1FF0.903#CADFFF0.898

The differences are modest for a blue and white, but they grow with more saturated or more distant colours, and OKLCH mixes keep a predictable lightness. You can also control how the hue travels when two colours have different hues: in oklch longer hue takes the long way around the wheel, and shorter hue is the default. Linear gradients accept the same interpolation hint, for example linear-gradient(in oklch, red, blue).

Browser support

oklch() is supported in all current major evergreen browsers: Chrome and Edge from version 111, Safari from 15.4 and Firefox from 113. Support for color-mix() and, later, relative colour syntax followed in each of them, so the safest approach is to check the individual feature. Can I use and the MDN page for oklch() track the current state, including older browsers and in-app web views.

Support for the function does not guarantee that a wide-gamut colour is displayed in full. That also depends on the screen. A browser that understands oklch(0.7 0.3 150) on a standard monitor will render the nearest colour it can show, and a conversion to hex shows what that is.

A safe fallback pattern

CSS ignores declarations it cannot parse, so the simplest fallback is to write the hex value first and the oklch() value after it. A browser that does not understand oklch() discards the second line and keeps the first. For groups of declarations, or for features like relative colours that can parse differently, wrap them in @supports.

Fallback with @supports

:root {
  --brand: #2b7fff;                  /* hex for everyone */
}
@supports (color: oklch(0 0 0)) {
  :root {
    --brand: oklch(0.623 0.214 259.8);
  }
}
.button {
  background: var(--brand);
}

Generate the hex from the OKLCH value instead of choosing it separately, so the two never disagree by accident. The OKLCH to HEX converter does this, and if the colour is outside sRGB the hex is its mapped approximation.

OKLCH in Tailwind CSS v4

Tailwind CSS v4 defines its default palette in OKLCH. The 286 family-and-step colour stops in the installed theme are written as CSS custom properties such as --color-blue-500: oklch(0.623 0.214 259.8), which is why utilities like bg-blue-500 already produce OKLCH output. You can browse every stop on the Tailwind v4 colours page, see how each one differs from the v3 hex values in the v3 to v4 mapping, and read how shadcn/ui themes use the same notation.

FAQ

What is the correct oklch() syntax?
Write oklch(L C H) with spaces, for example oklch(0.62 0.21 260), and add / alpha for opacity, for example oklch(0.62 0.21 260 / 0.5). L can be a number from 0 to 1 or a percentage, C is a number or a percentage, and H is an angle in degrees by default.
Do I need a fallback for oklch()?
For current evergreen browsers, no, but a fallback is cheap and protects older browsers and embedded web views. Write a hex declaration first, then the oklch() declaration, or wrap oklch values in @supports (color: oklch(0 0 0)).
What is relative colour syntax?
It is a way to derive a colour from another one: oklch(from var(--x) l c h) reads the lightness, chroma and hue of --x, and you can replace or adjust any of them, for example calc(l + 0.1). It is newer than oklch() itself, so check support before relying on it without a fallback.
Is color-mix() better in OKLCH than in sRGB?
For tints, shades and gradients, usually yes. Mixing in OKLCH changes lightness smoothly and avoids many of the dull or shifted midpoints that sRGB mixing produces. The differences are small for similar colours and larger for strongly different ones.
What happens if an oklch() colour is outside sRGB?
The browser maps it to a colour the display can show. On a wide-gamut screen you may see more of the colour, and on a standard screen the chroma is reduced. Convert it to hex to see the sRGB approximation.

Try it

Choose a colour visually, then copy it as an oklch() value or a hex fallback to paste into your stylesheet.

Open the OKLCH picker

← All guides