Skip to main content
PocketToolz

HEX, RGB, HSL and OKLCH: which colour format to use

Four ways to write the same colour, and why the newest one finally makes lightness mean what you expect.

6 min read

#3b82f6, rgb(59 130 246), hsl(217 91% 60%) and oklch(0.62 0.19 259) are all the same blue. They differ in what they let you do with it — and one of them fixes a problem the others have had for decades.

HEX and RGB are the same thing

Both say how much red, green and blue to mix. HEX writes each channel as two hexadecimal digits from 00 to ff; RGB writes the same numbers in decimal, 0 to 255. #ff0000 and rgb(255 0 0) are identical instructions.

HEX is compact and pastes cleanly between design tools. RGB is readable and takes an alpha channel naturally. Neither is better; pick one and be consistent.

The trouble with both is that the numbers do not correspond to anything you can reason about. Make this blue 20% lighter — which of the three numbers do you change, and by how much? There is no answer, which is why adjusting colour in HEX means guessing and re-checking.

HSL describes colour the way people do

Three numbers that each mean something:

  • Hue — 0 to 360 degrees around a colour wheel. Red 0, green 120, blue 240.
  • Saturation — 0% grey, 100% fully vivid.
  • Lightness — 0% black, 100% white, 50% the pure hue.

Now the questions have answers. A lighter version is the same colour with higher lightness. A muted version drops the saturation. A complementary colour is the hue plus 180. This is why HSL is what people reach for when building a palette.

Where HSL falls down

Its lightness number does not match perceived brightness. hsl(60 100% 50%) is yellow and hsl(240 100% 50%) is blue — same stated lightness, and the yellow is dazzling while the blue is nearly black.

The consequence is practical: a palette generated by holding lightness constant and rotating hue produces swatches that look wildly uneven, and text contrast that passes on one and fails on another. Anyone who has built a colour scale in HSL has hit this and had to hand-correct it.

OKLCH fixes exactly that

OKLCH takes the same three ideas — lightness, chroma, hue — and defines them against how human vision actually works rather than against the maths of a monitor. Its lightness is perceptual: two colours with the same L look equally bright, whatever their hue.

That makes several previously annoying things straightforward:

  • A colour scale at even lightness steps genuinely looks even.
  • Rotating hue at fixed lightness keeps contrast stable, so accessibility does not break for one brand colour.
  • Blending two colours passes through sensible intermediates instead of the grey mud RGB interpolation produces.

It also reaches colours that HEX and RGB cannot express at all — modern displays cover a wider gamut than sRGB, and OKLCH can address it.

Browser support is now good across the board. This site’s own palette is defined in OKLCH for these reasons.

Which to use

  • Pasting a brand colour someone gave you — HEX. It is what they will send.
  • Needing transparency — RGB or HSL with an alpha value.
  • Building a palette or a set of shades — OKLCH, or HSL if you must, and check the result.
  • Doing anything where contrast matters — OKLCH, and then verify it.

You can convert between all of them with the colour picker, build a scale with the palette generator, and blend two colours to see the intermediates.

One thing worth checking regardless of format

Contrast is the accessibility requirement that gets missed most, and it is not a matter of taste — WCAG asks for a ratio of at least 4.5:1 between body text and its background, and 3:1 for large text. Mid-grey on white fails. Light grey on white fails badly.

It is also the one that is trivially checkable, so there is no reason to ship a page that fails it. Check a pair before you commit to it.

Tools for this

Everything below runs in your browser. Nothing is uploaded.