One color in every notation CSS has, with each row a complete value ready to paste. The input takes hex of 3, 4, 6 or 8 digits alongside the functional forms and the 148 keywords. Where a color sits outside sRGB the table deliberately stops agreeing with itself, and that disagreement is the interesting part of this page.
Every format comes from one parse, not from the row above it
The input is parsed once into sRGB channels held as floats from 0 to 1, plus alpha, and every row is computed from those rather than chained through the row above it. HSL and HWB are cylindrical restatements of those same three numbers. OKLab, OKLCH, LAB and LCH linearize the channels, multiply into CIE XYZ with a 3x3 matrix and convert from there, using the matrices in CSS Color 4. Nothing is rounded until it is printed, so the internal round trip is exact: over 200,000 random sRGB colors, hex to OKLCH and back returned the same hex every time. The four decimals on screen are a separate matter, covered under Common problems.
Why lab() and oklch() disagree about white
CSS lab() and lch() are defined on the D50 white point, while oklch(), oklab() and sRGB are D65. Converting between them takes a chromatic adaptation, not just a formula. D65 is roughly noon daylight near 6500 K, which is what displays are calibrated to. D50 is the warmer 5000 K white of print and ICC work, and CSS inherited it for lab() from the ICC profile connection space. Adaptation is the arithmetic for what a stimulus would have to be under the other illuminant to look like the same color; this page uses the Bradford matrices from CSS Color 4.
Skip that step and nothing fails loudly. White comes out as lab(100 -2.4 -19.39) instead of lab(100 0 0), sitting a fifth of the b axis into blue. It is the most common bug in color converters because the numbers still look plausible and disagree with other tools by only a few units. You can test any converter in five seconds: give it #ffffff and check that a and b both read 0.
What the sRGB gamut is, and how a color falls out of it
sRGB describes only the colors inside the triangle its three primaries span, while OKLCH, OKLAB, LAB and LCH describe any color a person can see. So an oklch() value is not guaranteed to be showable, and that is not an error in the value. Try the oklch(0.72 0.28 145) example above: that green wants more chroma than the sRGB green primary has, and the arithmetic returns a negative red channel, which is the equation saying the color is not available here.
Something has to give, and there are two ways to give it. Clipping each channel to 0 and 1 on its own, which is what browsers do today, lands on #00cd00, and that reads back as oklch(0.735 0.2501 142.5): the lightness moved and the hue moved 2.5 degrees. Reducing chroma at constant lightness and hue, the mapping CSS Color 4 specifies, lands on #00c737, which is oklch(0.72 0.2265 145). Same hue, and all that is lost is saturation that was never displayable.
This page does the second one. Out of gamut, the HEX, RGB, HSL and HWB rows carry the mapped color and say so, while the OKLCH, OKLAB, LAB and LCH rows keep what you entered with the mapped value on the row beneath. Few converters draw that distinction, which is how a vivid oklch() out of a design file quietly becomes a different hue in the stylesheet.
Why OKLCH is worth switching to
Two colors with the same OKLCH lightness look equally light. Two with the same HSL lightness do not, and it is not close. hsl(60 100% 50%) is yellow and hsl(240 100% 50%) is blue, and both claim a lightness of 50%. Their WCAG relative luminance is 0.9278 and 0.0722, which puts the contrast ratio between them at 8.0:1: you could set one as text on the other and read it at AAA. In OKLCH they are L 0.968 and L 0.452, which is the reading that matches what your eye reports. HSL's L is the midpoint of the largest and smallest sRGB channel, a fact about the encoding rather than about seeing. OKLab was fitted to perceptual data so that equal steps look equal, which is why a tonal scale stepped in OKLCH stays even where HSL turns muddy in the middle.
CMYK here is an approximation
No browser tool can give a print-accurate CMYK value, this one included. These four numbers are the standard arithmetic inversion of sRGB. A real separation depends on an ICC profile for a specific ink set, paper and press: the same values print differently on coated and uncoated stock, and the profile decides how much of the CMY under a dark area is replaced by black. If work is going to a printer, ask which profile they use (SWOP, FOGRA39, FOGRA51 and Japan Color are the usual answers) and take the numbers from them. Note the spelling too: device-cmyk() is CSS Color 5 and the only CMYK a stylesheet accepts.
Common problems
- The hex comes back one digit different. Copy the
oklch()value, paste it back, and about one sRGB color in 1,150 lands one 8-bit step off in one channel:#00fa9areturns as#01fa9a. That is the four printed decimals, not the conversion. Keep hex as the source of truth where a byte-exact round trip matters. - The last two hex digits are not a percentage.
#ff000080is 50.2% alpha, not 80%. The pair runs 00 to ff read as 0 to 255, so a clean 50% has no exact spelling. - A named color cannot be tuned. There are 148 keywords and nothing in between. Where the row says "nearest", the distance is measured in OKLab, where about 0.02 is the limit of what most people can tell apart. A keyword has nowhere to put alpha either, so that row drops it.
- Commas or spaces.
rgb(255, 0, 0)andrgb(255 0 0)both work in current browsers. This page emits the space form, which is the one that takesnonecomponents and a/ alphawithout switching torgba().
Frequently asked questions
Is hex the same thing as rgb()?
Yes. Both are 8 bits per channel of sRGB, so #ff8800 and rgb(255 136 0) are the same 24 bits written in different bases. Alpha included: #ff880080 is rgb(255 136 0 / 0.502).
Which format should I write in a stylesheet?
oklch() for anything you will manipulate: lightening, mixing, generating a scale. Hex or rgb() for fixed values a designer handed over. oklch() has been in every major browser since May 2023 (Safari 15.4, Chrome 111, Firefox 113).
Why do LAB and OKLAB report different lightness?
They are different scales fitted to different data. CIE Lab's L runs 0 to 100 and dates from 1976; OKLab's L runs 0 to 1 and was fitted in 2020, largely to fix the hue shifts Lab shows in blues. #1e90ff is L 58.36 in LAB and L 0.652 in OKLAB. 58.36 divided by 100 is not 0.652, and that gap is the correction rather than a rounding error.
Does converting lose anything, and is it private?
Going to HEX or RGB quantizes to one of 16,777,216 values, so a lab() with fractional precision snaps to the nearest 8-bit color. Everything else is lossless within float precision, and alpha carries through every format that supports it. Every conversion runs in this tab: no color is sent anywhere to be converted, and the ?c= parameter in the address bar is the only place the one you typed goes. The rest of the color tools work the same way.