What L, C and H Mean in Your Input
An oklch() value is written oklch(L C H), optionally followed by / alpha. Each part has its own range:
- L, lightness — 0% is black and 100% is white. It can also be written as a number from 0 to 1, so 60% and 0.6 mean the same.
- C, chroma — 0 is grey and the number grows with colourfulness. CSS treats 0.4 as 100%, but no hue reaches that inside sRGB; the limit depends on hue and lightness.
- H, hue — an angle from 0 to 360 degrees. Values outside that range wrap around, and a grey can use
none.
The default input, oklch(60% 0.2 300), is a violet a little above mid-lightness, which converts to #955BE3.
OKLCH vs HEX: When You Still Need a Hex Code
OKLCH is the better format for working on a colour. Lightness follows perception, so changing L by 10 looks like roughly the same step anywhere on the scale; palettes built by stepping L at a fixed C and H stay even and keep their hue; and oklch() can describe wide-gamut colours that hex cannot.
Hex is still what a lot of the world expects:
- brand guidelines, style guides and design-tool colour fields;
- HTML email and older software that predates oklch();
- colour lookups and print handoff, including this site's HEX to Pantone converter.
So a common workflow is to design in OKLCH and convert the final values to hex for documentation and fallbacks. For the opposite direction, the HEX to OKLCH converter turns an existing palette into oklch() values.
When an OKLCH Colour Has No Exact Hex Code
Hex codes cover the sRGB gamut, the range of a standard screen. oklch() has no such limit, so a high chroma, especially at very light or very dark lightness, can describe a colour no hex code reaches. Converting it directly gives red, green or blue values below 0 or above 255.
There are two ways to bring such a colour into range. Clipping cuts each channel to 0–255 separately, which can change the colour noticeably. Gamut mapping, the method CSS Color 4 specifies, lowers chroma while holding lightness and hue, and stops once the remaining clip changes the colour by less than a just-noticeable difference. Take oklch(70% 0.4 150):
- gamut-mapped, it is #00C248, which is
oklch(70.91% 0.21039 147.06); - clipped, it is #00D600.
The mapped hue lands at 147.06° rather than 150°, and lightness moves slightly too, because the method returns the clipped colour once it is close enough. The gamut check beside the converter shows both values whenever your input is outside sRGB.
Using oklch() in CSS With a Hex Fallback
Put the hex code from this converter first and the oklch() value second. A browser that understands oklch() uses the later declaration; one that does not keeps the hex:
.tag {
color: #955BE3;
color: oklch(60% 0.2 300);
}For a colour outside sRGB, the fallback is the gamut-mapped hex, and the oklch() value can be kept for screens that show more:
.cta {
background: #00C248;
background: oklch(70% 0.4 150);
}On a standard screen the browser has to bring the oklch() line into range itself, and browsers do not all do that the same way: some clip, so the result can differ from the gamut-mapped hex. On a wide-gamut screen the browser can show more of the chroma the oklch() value asks for.
Browser Support
oklch() is supported in Chrome and Edge from version 111, Safari from 15.4 and Firefox from 113. That leaves older browsers and many non-browser tools, which is why the hex fallback above is still worth writing.
OKLCH to HEX Reference Values
These oklch() values convert to the extremes, the three sRGB primaries and this site's brand purple. All are inside sRGB, so each gives its hex code exactly; they were computed when the page was built.
| Colour | oklch() | HEX | rgb() |
|---|---|---|---|
| White | oklch(100% 0 0) | #FFFFFF | rgb(255, 255, 255) |
| Black | oklch(0% 0 0) | #000000 | rgb(0, 0, 0) |
| Red | oklch(62.8% 0.25768 29.23) | #FF0000 | rgb(255, 0, 0) |
| Green | oklch(86.64% 0.29483 142.5) | #00FF00 | rgb(0, 255, 0) |
| Blue | oklch(45.2% 0.31321 264.05) | #0000FF | rgb(0, 0, 255) |
| Brand purple | oklch(64.57% 0.23988 316.07) | #C44EED | rgb(196, 78, 237) |
The primaries mark the edge of sRGB for their hues: raise the chroma of the red row to 0.3 at the same lightness and hue, and gamut mapping brings it straight back to #FF0000.
How We Calculate
OKLCH is turned into OKLab (a and b come from chroma and hue), then into linear sRGB with the inverse of the matrices in Björn Ottosson's OKLab article, and finally gamma-encoded for an sRGB (D65) screen. A colour counts as inside sRGB if every channel is within 0.02 of an 8-bit level of the 0–255 range, which absorbs floating-point error.
Outside that range, the colour is mapped with the binary-search algorithm in CSS Color 4: chroma is searched to a resolution of 0.0001, and the result is accepted once clipping it moves the colour by less than 0.02 in OKLab distance. Lightness of 100% or more gives white and 0% or less gives black, as the specification requires. Each channel is then rounded to the nearest whole number.
oklch() strings on this page are printed with lightness to 2 decimals, chroma to 5 and hue to 2, which is enough for every hex code to survive a round trip. The Pantone panel uses the weighted RGB ranking from our Pantone converters; treat its matches as approximate.