Colour space converter (OKLCH, OKLab, Lab, LCH, HWB, Display P3)
Convert any CSS colour to OKLCH, OKLab, Lab, LCH, HWB, Display P3 and XYZ, check the sRGB gamut and see CSS gamut mapping beside clipping.
A clear answer. Here’s how.
Parses the colour with the CSS Color Module Level 4 grammar: named colours, hex with optional alpha, rgb() and hsl() in comma or space syntax, hwb(), lab(), lch(), oklab(), oklch() and color() in srgb, srgb-linear, display-p3, xyz, xyz-d65 and xyz-d50. Values are clamped where the specification clamps them at parse time (rgb channels to 0–255, Lab and OKLab lightness to 0–100% and 0–1, negative chroma and saturation to 0) and none counts as 0. Every conversion goes through CIE XYZ with the matrices and the sRGB transfer function of the specification’s sample code; Lab and LCH use the D50 white with Bradford adaptation from D65, OKLab and OKLCH use the recalculated 64-bit matrices. A hue is powerless (shown as none) when LCH chroma is at most 0.0015 or OKLCH chroma at most 0.000004; hsl() and hwb() write 0 instead. A channel within 0.00001 of 0–1 counts as inside a gamut. Out of gamut, the colour is clipped (each channel clamped) and also gamut-mapped with the CSS algorithm of section 14.2: a binary search on OKLCH chroma at constant lightness and hue that stops when clipping moves the colour by less than one just-noticeable difference (ΔEOK 0.02, ε 0.0001). HEX, rgb(), hsl() and hwb() are written for the colour mapped into sRGB. CSS strings are rounded (4 decimals for 0–1 values, 3 for Lab and LCH, 2 for hues and percentages). Some worked examples in the specification were computed with older matrices and differ in the second or third decimal place; for example it gives sRGB blue as lab(29.567% 68.298 -112.0294) where the current sample code gives a = 68.287. This is the specification’s gamut mapping, not an ICC colour-management system, and the swatches are only as accurate as your screen.
How this is checked
5 reference checks passed These 5 cases were run when this page was built, on 20 October 2026, and all reproduce within the stated tolerance. The same cases are part of the automated tests that run on every change to Toolmoz. Engine version 1.
See the checks and where each expected answer comes from
Case 1
- Inputs
- CSS colour #7654CD
- Expected, and what Toolmoz gave
- Lab L expected 44.36, Toolmoz 44.35772389400392Lab a expected 36.05, Toolmoz 36.047904790759866Lab b expected -58.99, Toolmoz -58.98589914832903
- Where the expected answer comes from
- CSS Color 4 sections 10.9 and 11.1 example: #7654CD is lab(44.36% 36.05 -58.99), given to 2 decimals
- Allowed difference
- ±0.005
Case 2
- Inputs
- CSS colour oklch(65% 0.15 270)
- Expected, and what Toolmoz gave
- HEX expected #6c88ea, Toolmoz #6c88eaIn sRGB gamut expected Yes, Toolmoz YesDisplay P3 R expected 0.445, Toolmoz 0.4454065104577594Display P3 G expected 0.529, Toolmoz 0.5289817001454437Display P3 B expected 0.891, Toolmoz 0.8908736410962449
- Where the expected answer comes from
- CSS Color 4 example: oklch(65% 0.15 270) is #6c88ea and color(display-p3 0.445 0.529 0.891)
- Allowed difference
- ±0.0005
Case 3
- Inputs
- CSS colour oklch(65% 0.25 270)
- Expected, and what Toolmoz gave
- In sRGB gamut expected No, Toolmoz NosRGB R expected 0.3475, Toolmoz 0.34751396624490094sRGB G expected 0.4707, Toolmoz 0.47070864905551263sRGB B expected 1.146, Toolmoz 1.145573161012572Gamut-mapped R expected 0.37578, Toolmoz 0.37577848163976707Gamut-mapped G expected 0.50121, Toolmoz 0.5012146677664076Gamut-mapped B expected 1, Toolmoz 1
- Where the expected answer comes from
- CSS Color 4 example: oklch(65% 0.25 270) is color(srgb 0.3475 0.4707 1.146), outside sRGB; the mapped colour 0.37578 0.50121 1 comes from a separate Python implementation of the section 14.2.2 binary search
- Allowed difference
- ±0.0005
Case 4
- Inputs
- CSS colour color(display-p3 1.1 0.4 0.2)Gamut to check and map into display-p3
- Expected, and what Toolmoz gave
- In Display P3 gamut expected No, Toolmoz NoGamut-mapped R expected 1, Toolmoz 1Gamut-mapped G expected 0.473, Toolmoz 0.47283369053218643Gamut-mapped B expected 0.314, Toolmoz 0.3141618861962148
- Where the expected answer comes from
- CSS Color 4 section 14.2 example: on a Display P3 screen color(display-p3 1.1 0.4 0.2) becomes color(display-p3 1 0.473 0.314)
- Allowed difference
- ±0.0005
Case 5
- Inputs
- CSS colour color(xyz-d65 1 0 0)
- Expected, and what Toolmoz gave
- OKLab L expected 0.45, Toolmoz 0.44993670717466977OKLab a expected 1.236, Toolmoz 1.2357583799754628OKLab b expected -0.019, Toolmoz -0.018981916810331623
- Where the expected answer comes from
- Ottosson's table of XYZ and Oklab pairs: X 1, Y 0, Z 0 gives L 0.450, a 1.236, b -0.019 (3 decimals)
- Allowed difference
- ±0.0006
What this shows: the engine reproduces independently worked values for these cases. It does not prove every possible input is right. To test an answer you were given, see how to check a number; to see what is and is not checked across Toolmoz, see the accuracy ledger.
See a worked example
Worked example
A fixed demonstration, separate from the values you enter above.
- CSS colour
- oklch(65% 0.25 270)
- Gamut to check and map into
- sRGB (ordinary screens, the web default)
Example result
| Format | CSS | Note |
|---|---|---|
| Input | oklch(65% 0.25 270) | |
| HEX | #6080ff | Of the colour gamut-mapped into sRGB; the input is outside sRGB. |
| RGB | rgb(95.82 127.81 255) | Gamut-mapped into sRGB. |
| HSL | hsl(227.94 100% 68.79%) | Gamut-mapped into sRGB. |
| HWB | hwb(227.94 37.58% 0%) | Gamut-mapped into sRGB. |
Clipping moves the colour 0.0547 ΔEOK and CSS gamut mapping 0.0591; one just-noticeable difference is 0.02. CSS strings are rounded; the API values carry full precision. Swatches on screen are only as accurate as the display.