Guide · Colour models

HEX, RGB, HSL and OKLCH: which colour notation to use, and when

Four ways of writing the same colour, each good at something different. Knowing which is which turns colour from guesswork into arithmetic.

They all describe the same thing

#3DB3CB, rgb(61 179 203) and hsl(190 55% 52%) are the same teal. What changes is what the numbers mean — and therefore what becomes easy to do. HEX is compact, RGB matches how a screen physically works, HSL matches how designers think, and OKLCH matches how eyes actually perceive lightness. Use whichever makes the next edit easiest.

HEX: the shorthand everyone recognises

A hex code packs three values — red, green and blue, each from 0 to 255 — into six hexadecimal digits, two per channel. #3DB3CB is red 3D (61), green B3 (179), blue CB (203).

Hex is the right default for handing a colour to someone else — a client, a printer's brief, a design file, a bug report. It is a terrible format for editing by hand: nothing about #3DB3CB tells you how to make it 10% darker.

RGB: how the screen actually does it

Every pixel is three lights. rgb(61 179 203) sets them directly. Modern CSS uses space-separated values with an optional slash for alpha — rgb(61 179 203 / 0.5) — though the older comma form still works everywhere.

RGB earns its place when a value is being calculated rather than chosen: interpolating between two colours in JavaScript, reading pixels from a canvas, or working with an API that returns channels. For design decisions it has the same flaw as hex — the numbers do not map to anything you can see. Making a colour "a bit less intense" means moving all three channels in different amounts.

HSL: the one to think in

HSL rewrites the same colour as hue, saturation and lightness, and suddenly the numbers correspond to the sliders in your head.

Now the edits are obvious. Want a hover state? Drop lightness by 8%. Want a muted version for a disabled control? Halve the saturation. Want a complementary accent? Add 180 to the hue. This is exactly how the harmony modes in the generator work: they move the hue by fixed angles and vary lightness, which is why analogous, triadic and complementary palettes come out coherent rather than random.

:root {
  --brand:       hsl(190 55% 52%);
  --brand-hover: hsl(190 55% 44%);   /* same colour, darker  */
  --brand-quiet: hsl(190 28% 52%);   /* same colour, calmer  */
  --brand-comp:  hsl(10  55% 52%);   /* opposite on the wheel */
}

The catch with HSL, and what OKLCH fixes

HSL has one significant flaw: its lightness is a mathematical midpoint, not a perceived one. hsl(60 100% 50%) (yellow) and hsl(240 100% 50%) (blue) claim identical lightness, yet the yellow is blindingly bright and the blue is nearly black. Build a five-step scale by stepping lightness evenly and the steps will not look evenly spaced.

OKLCH is a newer CSS colour notation built on a perceptually uniform model. It takes lightness (0–1 or 0–100%), chroma (colourfulness, roughly 0–0.4) and hue (0–360°):

color: oklch(0.72 0.11 220);

Because its lightness axis tracks human perception, two colours with the same OKLCH lightness genuinely look equally light — which makes it far better for generating tonal scales, for dark-mode inversions and for accessible palettes. It also reaches colours outside sRGB on wide-gamut displays. Browser support is now broad across current versions of Chrome, Safari, Firefox and Edge, but if you support older browsers, ship a hex fallback first and let OKLCH override it.

Rule of thumb. Store and share colours as hex. Reason and edit in HSL. Generate tonal scales in OKLCH. Use RGB when code is doing the maths.

One more thing OKLCH quietly fixes: when a colour you have asked for falls outside what sRGB can display, naive conversion clips the red, green and blue channels independently, which shifts the hue — a deep teal can drift visibly blue. Reducing chroma while holding lightness and hue steady keeps the colour recognisably itself. That is what the tonal-scale generator does at the extremes of each scale.

What about CMYK and Pantone?

Both belong to print, and neither is a web format. CMYK is subtractive — ink on paper — and its gamut is smaller than your screen's, so vivid screen colours (bright cyans, electric greens, hot pinks) will always print duller than they look here. Pantone is a set of pre-mixed spot inks identified by number, used when a colour must be exact across every print run.

If a palette is heading for print, treat the hex value as a starting point only: hand it to your printer, ask for a CMYK conversion in the correct profile for the stock, and check a physical proof before you sign off. No screen preview, including this one, can tell you how ink will sit on paper.

Converting between them

You rarely need to do this by hand. The JUMI Colour Generator shows every swatch in hex, accepts a hex typed straight into any swatch, and copies palettes as HEX or RGB with one click. The export panel writes CSS custom properties, OKLCH, SCSS variables, a Tailwind config or JSON tokens with the values already formatted.

The OKLCH export writes each colour twice — hex first, then oklch() — so browsers that understand it take the second line and older ones keep the first. That is the fallback pattern described above, generated for you.

OKLCH also does quiet work underneath the Tonal scale panel: the ten steps are spaced along the Oklab lightness axis rather than the HSL one, which is exactly why they come out looking evenly separated.

Open the Colour Generator →

Related guides: Colour theory basics · Colour in a design system · Accessible colour