Every colour notation on the web ends up as three numbers driving red, green and blue subpixels. The notations differ in what those numbers mean to a person reading them, and that turns out to matter a great deal.
Hex and RGB are the same thing
#48750d is three pairs of hexadecimal digits — red 72, green 117, blue 13. rgb(72 117 13) is the same numbers in decimal. There is no difference in capability; hex is shorter and RGB is readable.
Both describe the hardware. Neither tells you anything useful about the colour: nothing in #48750d suggests it is a dark olive green, and adjusting it means guessing at three numbers that interact.
HSL made it readable
Hue as an angle, saturation and lightness as percentages. Suddenly you can reason about a colour — same hue, less saturation — and generate a palette by holding the hue and stepping the lightness.
That was the promise, and it half worked. The problem is that HSL is computed from RGB with straightforward arithmetic that knows nothing about human vision.
Where HSL lightness lies
Your eye is far more sensitive to green than to blue. Pure yellow at hsl(60 100% 50%) and pure blue at hsl(240 100% 50%) have the same stated lightness, and one of them is nearly white while the other is nearly black.
The consequences show up everywhere once you look. A palette built by stepping HSL lightness has uneven steps — crowded at one end, spread at the other. A hue rotation at fixed lightness swings visibly brighter and darker as it goes round. And a colour that passes a contrast check at one hue fails at another with identical HSL numbers, because contrast is computed from real luminance and HSL is not.
What OKLCH fixes
Same three ideas — lightness, chroma, hue — built on a perceptual model rather than on RGB arithmetic.
L is perceived lightness, so two colours at the same L genuinely look equally light. C is chroma, how colourful, and unlike saturation it is not a percentage of anything — it has an absolute scale, and how much of it is available depends on the lightness and the hue. H is the hue angle.
Which makes the things people actually do straightforward. A palette of even steps is even. A hue rotation holds its brightness. Two brand colours can be matched for lightness by making one number equal.
The chroma point has a real consequence worth knowing: dark greens cannot be very chromatic. Not a limitation of the notation but of the colour space — and it is exactly why a green dark enough to pass a contrast requirement against white reads as olive-grey whatever you do to it.
Colours outside sRGB
OKLCH can describe colours no ordinary screen can show, and modern displays can show more than sRGB covers.
So a conversion from OKLCH to hex may have nothing exact to return, and clips to the nearest colour in range. Converting hex to OKLCH is always exact, because hex cannot describe anything OKLCH cannot.
Practically: author in OKLCH, and treat the hex your converter gives you as the sRGB rendering rather than as the same colour.
Which to use
Hex for a value you are copying between tools. Compact, universal, and fine as an output format.
RGB when you need alpha and readability together, though every notation supports alpha now.
HSL if it is already in the codebase and working. It is not wrong; it just misleads you about lightness.
OKLCH for anything you are designing rather than transcribing: palettes, colour scales, tokens, dark mode variants. Browser support is broad enough to author in directly.
The short version
Hex and RGB describe hardware. HSL is readable and its lightness does not match your eye. OKLCH does, which is why palettes built in it come out even and palettes built in HSL need hand-correcting.
And whichever you author in, check the result against a contrast requirement rather than assuming a lightness number implies one.