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

> HEX and RGB give red, green and blue. HSL gives hue, saturation and lightness. OKLCH gives perceptual lightness, chroma and hue. With conversion tables.

- URL: https://generate.now/guides/hex-vs-rgb-vs-hsl-vs-oklch
- Published by: Hyperdusk Ltd (https://hyperdusk.com)
- Published: 2026-11-11
- Last updated: 2026-11-11

## 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.

## Key differences

**HEX, RGB, HSL and OKLCH side by side**

|   | HEX | rgb() | hsl() | oklch() |
| --- | --- | --- | --- | --- |
| Components | Red, green, blue as base-16 pairs | Red, green, blue from 0 to 255 | Hue angle, saturation, lightness | Lightness, chroma, hue angle |
| The same color | #1e90ff | rgb(30, 144, 255) | hsl(210, 100%, 56%) | oklch(65.2% 0.190 253.2) |
| Color space | sRGB | sRGB | sRGB | Oklab |
| Can describe colors outside sRGB | No | No | No | Yes |
| Lightness matches what the eye sees | Not applicable | Not applicable | No | Yes, by design |
| Good for | Copying an exact value between tools | Working with channel values in code | Quick tints and shades of one hue | Palettes 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() value | HEX | OKLCH lightness | Contrast with white |
| --- | --- | --- | --- |
| `hsl(0, 100%, 50%) red` | `#ff0000` | 62.8% | 4.00:1 |
| `hsl(60, 100%, 50%) yellow` | `#ffff00` | 96.8% | 1.07:1 |
| `hsl(120, 100%, 50%) green` | `#00ff00` | 86.6% | 1.37:1 |
| `hsl(180, 100%, 50%) cyan` | `#00ffff` | 90.5% | 1.25:1 |
| `hsl(240, 100%, 50%) blue` | `#0000ff` | 45.2% | 8.59:1 |
| `hsl(300, 100%, 50%) magenta` | `#ff00ff` | 70.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**

| HEX | rgb() | hsl() | oklch() |
| --- | --- | --- | --- |
| `#ff0000` | `rgb(255, 0, 0)` | `hsl(0, 100%, 50%)` | `oklch(62.8% 0.258 29.2)` |
| `#ffff00` | `rgb(255, 255, 0)` | `hsl(60, 100%, 50%)` | `oklch(96.8% 0.211 109.8)` |
| `#0000ff` | `rgb(0, 0, 255)` | `hsl(240, 100%, 50%)` | `oklch(45.2% 0.313 264.1)` |
| `#1e90ff` | `rgb(30, 144, 255)` | `hsl(210, 100%, 56%)` | `oklch(65.2% 0.190 253.2)` |
| `#663399` | `rgb(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

- [Convert a color between HEX, RGB, HSL and OKLCH](https://generate.now/color): Color Picker & Converter. Converts one color between all four notations, flags an OKLCH value that is outside sRGB, and shows its contrast against white and black.
- [Generate a color palette from a description](https://generate.now/palette): Color Palette Generator. Builds a palette from a text prompt.
- [Build a CSS gradient](https://generate.now/gradient): CSS Gradient Generator. Creates linear, radial and conic gradients and outputs the CSS.

## Sources

Primary sources, read on 2026-11-11.

- [CSS Color Module Level 4](https://www.w3.org/TR/css-color-4/): W3C. Hex notation, rgb(), hsl() and its limits, oklch() component ranges, gamut definitions, gamut mapping and the gamut-volume table.
- [oklch()](https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Values/color_value/oklch): MDN Web Docs. The oklch() syntax and the ranges of its lightness, chroma and hue components.

## Related guides

- [UUID v4 vs v7: Differences and Which to Use](https://generate.now/guides/uuid-v4-vs-v7): UUID v4 is 122 random bits. UUID v7 starts with a millisecond timestamp, so IDs sort by creation time. Bit layouts, collision odds and when to use each.
- [UUID vs ULID vs Nano ID: Size, Sorting and Collisions](https://generate.now/guides/uuid-vs-ulid-vs-nanoid): UUID, ULID and Nano ID compared: length, alphabet, random bits, whether they sort by time, and computed collision odds. With a guide to choosing one.
- [Password vs Passphrase: Which Is Stronger?](https://generate.now/guides/password-vs-passphrase): A random 12-character password and a six-word passphrase are about equally strong. Entropy tables for both, and what NIST SP 800-63B says about length.

[All guides](https://generate.now/guides)
