Color on the web used to mean hex codes and sRGB. Modern CSS supports several color systems with meaningfully different ergonomics and capabilities. This guide explains what each system is, when to use it, and how to mix them safely.
The Systems at a Glance
| System | Syntax | Gamut | Best for |
|---|---|---|---|
| Hex | #ff6633 | sRGB | Concise; ubiquitous |
| RGB | rgb(255 102 51) | sRGB | Direct channel control |
| HSL | hsl(15 100% 60%) | sRGB | Hue rotation, simple palettes |
| LCH | lch(60% 80 30) | Wide | Perceptually uniform |
| OKLCH | oklch(0.6 0.2 30) | Wide | Modern design systems |
| Display P3 | color(display-p3 1 0.4 0.2) | P3 | Vivid colors on modern displays |
Perceptual Uniformity Matters
The reason designers are moving from HSL to OKLCH: HSL's lightness is mathematically simple but perceptually broken. hsl(60 100% 50%) (yellow) and hsl(240 100% 50%) (blue) have the same L value but look completely different in brightness. OKLCH fixes this — equal L produces equal perceived brightness across all hues. This makes scales, gradients, and contrast much more reliable.
Wide-Gamut Color
Most screens since ~2017 support Display P3, a wider gamut than sRGB. You can author colors outside sRGB using oklch(), color(display-p3 ...), or lab(). Browsers clip to the display gamut gracefully. The practical effect: more saturated reds and greens than sRGB can produce.
A Modern Color Workflow
- Author in OKLCH for clarity and perceptual uniformity.
- Provide hex fallbacks for older browsers if you support them.
- Define color tokens (--brand-500, etc.) using OKLCH; use them everywhere downstream.
- Build scales by varying L while holding C and H — produces uniform brightness steps.
- Test contrast pairs early and lock them into your token system.
Converting Between Systems in Practice
You rarely convert by hand, but knowing how the systems relate prevents nasty surprises:
- Hex and RGB are the same thing in different clothing —
#3366ccis exactlyrgb(51 102 204). Hex is just two hexadecimal digits per channel. - HSL is a reversible transform of RGB, so converting back and forth is lossless; both describe sRGB colours.
- OKLCH and Lab can describe colours outside sRGB, so converting a wide-gamut colour down to hex is lossy — it gets clipped into the smaller sRGB box.
- Let CSS do the work: modern browsers accept
oklch()directly, andcolor-mix()blends across spaces, so author in whichever space is easiest to reason about and ship that.
The takeaway: pick one authoring space (OKLCH for new work), keep a hex fallback for reach, and avoid round-tripping wide-gamut colours through hex, which silently dulls them.
Try It Yourself
Extract palettes from images and explore color relationships with DesignKit tools.
Color Palette Extractor →