Skip to content

HEX vs RGB vs HSL vs OKLCH: CSS Color Formats Compared

Last updated Published by Hyperdusk Ltd

The short answer

HEX and rgb() say the same thing: amounts of red, green and blue in sRGB. hsl() rearranges those into hue, saturation and lightness, which is easier to adjust by hand. oklch() uses perceptual lightness, chroma and hue, so equal lightness values look equally light, and it can describe colors outside sRGB.

Convert a color between HEX, RGB, HSL and OKLCH →

Key differences

HEX, RGB, HSL and OKLCH side by side
HEXrgb()hsl()oklch()
ComponentsRed, green, blue as base-16 pairsRed, green, blue from 0 to 255Hue angle, saturation, lightnessLightness, chroma, hue angle
The same color#1e90ffrgb(30, 144, 255)hsl(210, 100%, 56%)oklch(65.2% 0.190 253.2)
Color spacesRGBsRGBsRGBOklab
Can describe colors outside sRGBNoNoNoYes
Lightness matches what the eye seesNot applicableNot applicableNoYes, by design
Good forCopying an exact value between toolsWorking with channel values in codeQuick tints and shades of one huePalettes and gradients with even lightness
The example row was converted with the code behind the generate.now color converter.

Are HEX and RGB the same thing?

Yes. A six-digit hex color is three two-digit base-16 numbers for red, green and blue, each from 00 to ff, which is 0 to 255. #1e90ff and rgb(30, 144, 255) are the same sRGB color written two ways, and six digits give 16,777,216 possible colors.

CSS Color 4 accepts 3, 4, 6 or 8 hex digits. The three-digit form is shorthand in which each digit is doubled. The fourth or the seventh and eighth digits are alpha: the specification's example is #0000ffcc, a blue at 80% opacity. Letter case does not matter.

What does HSL change?

Nothing about which colors are available: hsl() still describes sRGB. It changes the controls. The specification calls RGB "very difficult for humans to gain an intuitive grasp on" and HSL "more intuitive", because you can keep the hue and vary saturation and lightness to get lighter, darker or more muted versions of a color.

Its weakness is that HSL lightness is arithmetic on the RGB values and does not match perceived lightness. The six colors below all have an HSL lightness of 50%.

Six colors that HSL calls 50% light
hsl() valueHEXOKLCH lightnessContrast with white
hsl(0, 100%, 50%) red#ff000062.8%4.00:1
hsl(60, 100%, 50%) yellow#ffff0096.8%1.07:1
hsl(120, 100%, 50%) green#00ff0086.6%1.37:1
hsl(180, 100%, 50%) cyan#00ffff90.5%1.25:1
hsl(240, 100%, 50%) blue#0000ff45.2%8.59:1
hsl(300, 100%, 50%) magenta#ff00ff70.2%3.14:1
Computed with apps/web/lib/color.ts, the code behind the generate.now color converter. Contrast is the WCAG 2 contrast ratio. The blue and yellow lightness values match the example in CSS Color 4.

Yellow and blue have the same HSL lightness, but white text stands out on the blue (8.59:1) and almost disappears on the yellow (1.07:1). A palette built by rotating the HSL hue therefore has uneven contrast.

What is OKLCH, and why use it?

oklch() describes a color in the Oklab color space using three numbers. L is lightness from 0 to 1, or 0% to 100%. C is chroma, the amount of color: it starts at 0 for gray, and the specification says it is theoretically unbounded but in practice does not exceed 0.5. H is a hue angle in degrees.

Oklab was designed to be perceptually uniform, so two colors with the same L look about equally light whatever their hue. That makes it straightforward to build a set of colors with consistent contrast, and CSS Color 4 points to Oklab for cases where colors need to be evenly spaced perceptually, such as a gradient.

Hue angles are not the same numbers as in HSL. Pure red is 0 in HSL and 29.2 in OKLCH; pure blue is 240 and 264.1.

The same colors in each notation
HEXrgb()hsl()oklch()
#ff0000rgb(255, 0, 0)hsl(0, 100%, 50%)oklch(62.8% 0.258 29.2)
#ffff00rgb(255, 255, 0)hsl(60, 100%, 50%)oklch(96.8% 0.211 109.8)
#0000ffrgb(0, 0, 255)hsl(240, 100%, 50%)oklch(45.2% 0.313 264.1)
#1e90ffrgb(30, 144, 255)hsl(210, 100%, 56%)oklch(65.2% 0.190 253.2)
#663399rgb(102, 51, 153)hsl(270, 50%, 40%)oklch(44.0% 0.160 303.4)
Computed with apps/web/lib/color.ts. HSL values are rounded to whole numbers, OKLCH to one decimal place of lightness and hue and three of chroma.

What is a gamut, and when does it matter?

A gamut is the range of colors a color space or a screen can produce. HEX, rgb() and hsl() can only name colors inside sRGB. oklch() can name colors beyond it, which wide-gamut screens can show. CSS Color 4 puts the volume of sRGB at 0.820 million Lab units and Display P3 at 1.233 million.

A color can be valid CSS and still be out of gamut for the screen showing it. The specification says such a color is gamut mapped for display, giving a similar-looking color with lower chroma. For example, oklch(70% 0.3 150) is outside sRGB. Reducing its chroma until it fits, at the same lightness and hue, gives oklch(70.0% 0.193 150.0), which is #00be58.

That example was computed with the generate.now color converter's own gamut check, which reduces chroma by binary search. Browsers may use a different mapping method and land on a slightly different color.

Which should you use?

Use HEX or rgb() when you are handing an exact sRGB color to another tool, a design file or older code.

Use hsl() for a quick lighter or darker variant of a single hue. Use oklch() when you are building a palette, a scale or a gradient and want lightness and contrast to stay consistent across hues, or when you want colors outside sRGB. The formats can be mixed freely in one stylesheet.

Tools for this

Sources

This page was written from the primary sources below, read on .

  • CSS Color Module Level 4

    W3C. Hex notation, rgb(), hsl() and its limits, oklch() component ranges, gamut definitions, gamut mapping and the gamut-volume table.

  • oklch()

    MDN Web Docs. The oklch() syntax and the ranges of its lightness, chroma and hue components.

Published by Hyperdusk Ltd. Last updated . Figures in computed tables were produced by the method stated under each table.

All guides→