Updated July 10, 2026

The CSS oklch() Syntax Explained

The CSS oklch() function specifies a color by three space-separated values — Lightness, Chroma, Hue — with an optional alpha after a slash: oklch(0.55 0.15 260) or oklch(0.55 0.15 260 / 40%). It has been native CSS since 2023 and works in all major browsers without a build step. This is a working reference for the syntax; what the values mean perceptually is covered across our OKLCH guide.

What are the three values and their ranges?

color: oklch(L C H);
color: oklch(L C H / alpha);
  • L — Lightness. A percentage (0%100%) or a number (01); 62% and 0.62 are the same lightness. 0 is black, 1 is white.
  • C — Chroma. A non-negative number. In principle unbounded, in practice bounded by what screens can show: sRGB colors top out around 0.37, and everyday UI colors mostly live between 0 (gray) and 0.25. There is no meaningful “100% chroma” — the maximum depends on lightness and hue.
  • H — Hue. An angle in degrees (0360, unit optional): roughly 30 is red-orange, 145 green, 260 blue. Gray has no meaningful hue — write any number, or none.
  • alpha. After a /: a percentage or 01 number, same as elsewhere in CSS.

The formal grammar lives in the MDN reference for oklch(); the summary above covers what day-to-day styling needs.

What does a real component look like in oklch()?

A button, written entirely in the syntax:

.button {
  background: oklch(0.55 0.15 260);          /* mid-lightness blue        */
  color: oklch(0.98 0.01 260);               /* near-white, hint of hue   */
  border: 1px solid oklch(0.55 0.15 260 / 40%);  /* same blue at 40% alpha */
}

Two details are doing quiet work here. The text color carries 0.01 chroma in the button’s own hue — a near-white that belongs to the blue instead of a sterile #fff. And the border reuses the background color with alpha rather than a separately picked lighter blue, so it stays in step if the background changes.

How do you derive one color from another?

The relative color form takes an existing color apart into l, c, h channels you can modify:

:root {
  --brand: oklch(0.55 0.15 260);
}
.button:hover {
  background: oklch(from var(--brand) calc(l - 0.07) c h);  /* darker      */
}
.badge {
  background: oklch(from var(--brand) 0.95 calc(c / 3) h);  /* pale tint   */
}

This is where a perceptual model pays off in plain CSS: “hover is 0.07 darker” behaves the same whether the brand color is blue, green, or orange, because equal L-steps look equal. The same recipe in hex requires a hand-picked value per hue.

What do generated OKLCH values look like on a real ramp?

Reading raw values against real colors builds the intuition fastest. Open a ramp with each step’s L/C/H visible in Scale Composer — lightness falls step by step down one curve, chroma swells through the midtones and eases off at the ends, hue holds still. Three columns of numbers, three independent jobs.

A ten-step color ramp with each step's OKLCH lightness, chroma, and hue values displayed alongside the swatches

What about browsers that don’t support oklch()?

Support has been universal in major browsers since 2023, so fallbacks are a legacy-traffic question rather than a default requirement. When you need one, CSS’s cascade does the work — declare the fallback first:

.button {
  background: #4263c7;                /* used where oklch() is unknown */
  background: oklch(0.55 0.15 260);   /* wins everywhere else          */
}

Or gate larger blocks with @supports (color: oklch(0 0 0)). Token pipelines commonly sidestep the question by exporting hex alongside OKLCH, which keeps legacy CSS consumers working from the same palette.

Where does the syntax go beyond hex?

Hex stops at sRGB; the OKLCH model doesn’t. Flip the same ramp into Display-P3 mode and the steps carry color(display-p3 …) strings alongside their sRGB-clamped hex — the midtones gain chroma the hex column literally cannot express. Copy a pair of values for the same step and compare them in your own stylesheet: that gap between the two strings is the part of your screen’s gamut that hex-era CSS never reached.

Keep reading