CSS gives you several ways to write the same colour. They describe the colour from different angles, and choosing the right one makes colours easier to read, adjust and keep accessible.
Convert any colour: paste a value into the colour converter to get every format and a WCAG contrast check.
HEX: compact and universal
#3446d4 is three bytes in hexadecimal: red 34, green 46 and blue d4, each from 00 to ff (0–255). Short forms double each digit (#fff = #ffffff). A fourth or eighth digit adds alpha: #3446d480 is about 50% opaque.
Use it when you’re copying colours between tools, or for brand values. It’s hard to adjust by eye.
RGB: the same thing in decimal
rgb(52 70 212) is the same colour as #3446d4. Modern syntax separates values with spaces and adds alpha after a slash: rgb(52 70 212 / 50%). The older rgba(52, 70, 212, 0.5) still works.
HSL: hue, saturation, lightness
hsl(233 65% 52%) (our #3446d4 again): the hue is an angle on the colour wheel (0 red, 120 green, 240 blue), saturation is from grey to vivid, and lightness is from black through the pure colour to white.
Use it when you want quick hand adjustments, such as a lighter tint or a less saturated version. Its weakness: lightness isn’t perceived lightness. hsl(60 100% 50%) (yellow) looks far brighter than hsl(240 100% 50%) (blue), despite the same “50%”.
HWB: hue, whiteness, blackness
hwb(233 20% 17%) starts from a pure hue and mixes in white and black, a bit like mixing paint. It’s intuitive for picking tints and shades, but less common in codebases.
OKLCH: perceptual lightness, chroma, hue
oklch(50% 0.2 270) uses the OKLab colour space (Björn Ottosson, 2020), which is designed so equal numeric steps look like equal visual steps:
- L (lightness), 0–100%: perceived lightness. Two colours at 70% look about equally light, whatever their hue.
- C (chroma), from 0 upwards (usually up to about 0.37): colourfulness. 0 is grey.
- H (hue), 0–360°: the hue angle. It doesn’t line up exactly with HSL’s.
This makes OKLCH excellent for design systems. Keep L and C fixed and rotate H, and you get a set of accent colours with matching weight. Step L from 95% to 25%, and you get a tint-to-shade scale that looks even. It’s supported in current Chrome, Edge, Firefox and Safari.
One catch: OKLCH can describe colours that ordinary sRGB screens can’t show, especially at high chroma. Browsers map these to the nearest displayable colour, and wide-gamut (Display P3) screens can show more of them. The colour converter works in sRGB, and flags colours it had to clamp.
Contrast: making text readable
WCAG 2.x measures contrast as a ratio of the relative luminance of two colours, from 1:1 (identical) to 21:1 (black on white):
| Content | AA | AAA |
|---|---|---|
| Normal text | 4.5:1 | 7:1 |
| Large text (≈24px, or ≈19px bold) | 3:1 | 4.5:1 |
| UI components and graphics | 3:1 | — |
Values near the threshold matter. #777777 on white is 4.48:1 and fails AA for body text. #767676 is 4.54:1 and passes. Check real colour pairs instead of guessing. Semi-transparent text is checked after blending it with its background.
A newer contrast method, APCA, is being explored for future versions of WCAG. For now, the WCAG 2.x ratio is the one in standards and legal requirements.
A practical workflow
- Choose your brand colour in any format, and convert it to OKLCH with the colour converter.
- Build a scale by changing lightness in even steps, keeping chroma and hue similar. Lower the chroma slightly at the extremes, so colours stay in gamut.
- Check every text and background pair you plan to use for contrast. Keep a note of which pairs pass AA.
- Store the values as CSS custom properties. The converter can copy them in that form.
:root {
--brand-500: oklch(52% 0.2 268);
--brand-700: oklch(38% 0.16 268);
--text-on-brand: oklch(98% 0.01 268);
}