# HEX, RGB and HSL: one colour, three notations

> HEX and RGB are the same numbers in different notation - #2563eb is rgb(37, 99, 235), two hex digits per channel. HSL describes the same colour as hue, saturation and lightness, which makes generating consistent tints and shades trivial in a way HEX never is.

Source: https://rankcert.com/blog/hex-rgb-hsl-explained
Published: 2026-09-02 · Updated: 2026-09-02

---


Every colour on the web is three numbers describing how much red, green and blue light to emit. The notations differ; the colour does not.

## HEX is RGB in base 16

`#2563eb` is three pairs of hex digits. Each pair is one channel, 00 to ff, which is 0 to 255 in decimal.

- `25` = 37 red
- `63` = 99 green
- `eb` = 235 blue

So `#2563eb` and `rgb(37, 99, 235)` are identical. Converting by hand is just reading each pair as base 16.

Three-digit codes are shorthand where each digit doubles: `#f00` expands to `#ff0000`. It only reaches 4,096 colours, so it is useful for primaries and not much else.

Eight digits add alpha: `#2563eb80` is that blue at roughly 50% opacity. Modern CSS also accepts `rgb(37 99 235 / 50%)`, which does the same thing more legibly.

Free tool: [Color Converter](https://rankcert.com/tools/hex-to-rgb) - Convert HEX to RGB and back, get the HSL equivalent, and see the contrast ratio against white and black for accessibility checks.

## HSL is for building palettes

HSL describes the same colour as three perceptual properties:

- **Hue** - position on the colour wheel, 0 to 360 degrees
- **Saturation** - how far from grey, 0 to 100%
- **Lightness** - 0% is black, 100% is white, 50% is the pure hue

`#2563eb` is `hsl(221, 83%, 53%)`.

The reason this matters: to generate a set of tints and shades of one colour, hold hue and saturation constant and vary lightness. `hsl(221, 83%, 95%)` down to `hsl(221, 83%, 15%)` gives a coherent ramp in one line. Doing the same in HEX means guessing at 24 hex digits and getting a ramp that drifts in hue.

Every design system that generates colour scales does it in HSL or a perceptual space like OKLCH, never in HEX.

## OKLCH, briefly

HSL has a real flaw: equal lightness values do not look equally light. `hsl(60, 100%, 50%)` (yellow) is visibly brighter than `hsl(240, 100%, 50%)` (blue), despite both claiming 50%.

OKLCH fixes this by being perceptually uniform, and it is supported in every current browser. If you are building a colour system now, it is the better choice. HSL remains fine for adjusting a colour you already have.

## Contrast ratios

Contrast is computed from relative luminance, which weights the channels according to how sensitive the eye is to each: red 0.2126, green 0.7152, blue 0.0722. Green dominates, which is why green text on white fails contrast checks more easily than intuition suggests.

The ratio is `(lighter + 0.05) / (darker + 0.05)`, running from 1:1 to 21:1.

WCAG thresholds:

- **4.5:1** - body text, AA
- **3:1** - large text (18pt, or 14pt bold) and UI components, AA
- **7:1** - body text, AAA

Brand colours frequently fail. A mid-tone brand blue on white often lands around 3.5:1, which passes for headings and fails for body copy. The usual fix is to darken the text variant of the brand colour and keep the original for backgrounds and accents.

## Colour profiles

Screenshots and photographs are often in Display P3 or Adobe RGB, wider gamuts than sRGB. A canvas reads sRGB values, so a colour picked from a P3 screenshot will not exactly match what a design tool reports.

For web work this is rarely a problem, because the web is sRGB by default. It matters when you are matching a printed brand colour, where you want the Pantone or CMYK reference rather than a picked pixel.

Convert between notations, or lift a colour from an image, with the [HEX to RGB converter](/tools/hex-to-rgb) and the [image colour picker](/tools/image-color-picker).
