Web Color Systems: RGB, HSL, OKLCH, P3

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

SystemSyntaxGamutBest for
Hex#ff6633sRGBConcise; ubiquitous
RGBrgb(255 102 51)sRGBDirect channel control
HSLhsl(15 100% 60%)sRGBHue rotation, simple palettes
LCHlch(60% 80 30)WidePerceptually uniform
OKLCHoklch(0.6 0.2 30)WideModern design systems
Display P3color(display-p3 1 0.4 0.2)P3Vivid 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

  1. Author in OKLCH for clarity and perceptual uniformity.
  2. Provide hex fallbacks for older browsers if you support them.
  3. Define color tokens (--brand-500, etc.) using OKLCH; use them everywhere downstream.
  4. Build scales by varying L while holding C and H — produces uniform brightness steps.
  5. 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 — #3366cc is exactly rgb(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, and color-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 →

Frequently Asked Questions

RGB describes a colour by how much red, green and blue light the screen emits — the hardware's native channels. HSL re-expresses that same sRGB colour as hue, saturation and lightness, which is far easier to adjust by eye. They are mathematically interchangeable and render identically; HSL is just a friendlier set of dials on the same colour.
Perceptually uniform lightness — equal L values look equally bright across hues. More reliable for scales and contrast.
A wider color gamut than sRGB — supported by most displays since 2017. Use for vivid reds and greens.
Modern: OKLCH with hex fallback. Wide gamut: color(display-p3 ...) or oklch above sRGB.
WCAG contrast is always measured in luminance — identical regardless of authoring system.