Format Overview

The three most common CSS colour formats all represent colour in the sRGB colour space — they are simply different notations for the same underlying values:

  • HEX: #6c5ce7 — three pairs of hexadecimal digits for R, G, B
  • RGB: rgb(108, 92, 231) — three decimal values from 0 to 255
  • HSL: hsl(249, 72%, 63%) — hue (0–360°), saturation (0–100%), lightness (0–100%)

All three notate identical colours. Converting between them is a mathematical transformation with no information loss.

For a conceptual explanation of when to use each format, see our companion article: HEX vs RGB vs HSL: Understanding Web Color Formats for CSS.

HEX to RGB Conversion

HEX colour values use hexadecimal (base-16) notation. Each pair of digits represents a channel value from 0 (00 = decimal 0) to 255 (FF = decimal 255).

Algorithm

  1. Remove the leading #
  2. If shorthand (3 digits), expand to 6 digits: #abc → #aabbcc
  3. Split into three pairs: RR, GG, BB
  4. Convert each pair from hexadecimal to decimal using base-16 arithmetic

Example: #6c5ce7

  • 6c = (6 × 16) + 12 = 96 + 12 = 108
  • 5c = (5 × 16) + 12 = 80 + 12 = 92
  • e7 = (14 × 16) + 7 = 224 + 7 = 231

Result: rgb(108, 92, 231)

// JavaScript implementation
function hexToRgb(hex) {
  hex = hex.replace('#', '');
  if (hex.length === 3) {
    hex = hex.split('').map(c => c + c).join('');
  }
  const r = parseInt(hex.slice(0, 2), 16);
  const g = parseInt(hex.slice(2, 4), 16);
  const b = parseInt(hex.slice(4, 6), 16);
  return { r, g, b };
}

RGB to HSL Conversion

Converting RGB to HSL requires a three-step process. The algorithm normalises RGB values to the 0–1 range, then calculates lightness, saturation, and hue in sequence.

Algorithm

  1. Normalise: r' = R/255, g' = G/255, b' = B/255
  2. Find max and min of {r', g', b'}
  3. Lightness: L = (max + min) / 2
  4. Saturation: if max = min, S = 0 (achromatic). Otherwise: S = (max − min) / (1 − |2L − 1|)
  5. Hue (δ = max − min):
    • If max = r': H = 60 × ((g' − b') / δ) mod 6
    • If max = g': H = 60 × ((b' − r') / δ + 2)
    • If max = b': H = 60 × ((r' − g') / δ + 4)

Example: rgb(108, 92, 231)

  • Normalise: r'=0.424, g'=0.361, b'=0.906
  • max = 0.906 (b), min = 0.361 (g), δ = 0.545
  • L = (0.906 + 0.361) / 2 = 0.633 ≈ 63%
  • S = 0.545 / (1 − |2×0.633 − 1|) = 0.545 / (1 − 0.267) = 0.545 / 0.733 ≈ 74%
  • H = 60 × ((0.424 − 0.361) / 0.545 + 4) = 60 × (0.115 + 4) = 60 × 4.115 ≈ 247°

Result: approximately hsl(247, 74%, 63%)

function rgbToHsl(r, g, b) {
  r /= 255; g /= 255; b /= 255;
  const max = Math.max(r, g, b), min = Math.min(r, g, b);
  let h, s, l = (max + min) / 2;

  if (max === min) {
    h = s = 0;
  } else {
    const d = max - min;
    s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
    switch (max) {
      case r: h = ((g - b) / d + (g < b ? 6 : 0)) / 6; break;
      case g: h = ((b - r) / d + 2) / 6; break;
      case b: h = ((r - g) / d + 4) / 6; break;
    }
  }
  return {
    h: Math.round(h * 360),
    s: Math.round(s * 100),
    l: Math.round(l * 100)
  };
}

HSL to RGB Conversion

Converting from HSL back to RGB is needed when you want to apply a HSL colour using an older system or library that only accepts RGB values.

function hslToRgb(h, s, l) {
  s /= 100; l /= 100;
  const k = n => (n + h / 30) % 12;
  const a = s * Math.min(l, 1 - l);
  const f = n => l - a * Math.max(-1, Math.min(k(n) - 3, Math.min(9 - k(n), 1)));
  return {
    r: Math.round(f(0) * 255),
    g: Math.round(f(8) * 255),
    b: Math.round(f(4) * 255)
  };
}

RGB to HEX Conversion

Converting decimal RGB values back to hexadecimal is the reverse of HEX-to-RGB. Each channel value (0–255) is converted from decimal to a two-digit hexadecimal string.

function rgbToHex(r, g, b) {
  const toHex = n => n.toString(16).padStart(2, '0');
  return '#' + toHex(r) + toHex(g) + toHex(b);
}
// rgbToHex(108, 92, 231) → '#6c5ce7'
Skip the Math: All of these conversions are built into the ToolMasta Color Converter. Enter any colour in any format and instantly get all equivalent values. Useful for design-to-code workflows where your design tool gives you HEX but your CSS system uses HSL.

When to Use Each Format

HEX is the default format for design tools and is the most compact notation. Use it for communicating specific colour values in specifications, brand guidelines, and design-to-developer handoff. Most designers think in HEX.

RGB is useful when you need to work with individual channel values programmatically, or when integrating with systems (like canvas APIs or WebGL) that expect channel values as separate numbers.

HSL is the most human-readable format for developers creating and maintaining colour systems. The ability to say "this is a 70%-saturation, 60%-lightness violet" and independently adjust any axis makes it invaluable for design systems and dark mode implementations. For a detailed breakdown, see HEX vs RGB vs HSL: Understanding Web Color Formats for CSS.

Modern CSS Color Functions

The CSS Color Level 4 specification introduces several powerful colour functions beyond the classic three:

  • color(display-p3 r g b) — accesses wide gamut P3 colours, available on most modern displays
  • lab(L a b) — CIE Lab colour space, perceptually uniform
  • lch(L C H) — Lab polar form: lightness, chroma, hue
  • oklch(L C H) — improved Oklch space, perceptually uniform across all hues
  • oklab(L a b) — Oklab space, used internally for colour interpolation
  • color-mix(in oklch, red, blue) — mixes two colours in a specified colour space

The color() function also accepts the keyword srgb as a colour space, which is equivalent to standard rgb but uses fractional values: color(srgb 0.424 0.361 0.906).

oklch and Perceptually Uniform Colors

Oklch is the most exciting modern CSS colour format for developers building design systems. The key difference from HSL: equal lightness values appear equally bright across all hues.

In HSL, a yellow at 50% lightness (hsl(60, 100%, 50%)) appears much brighter to the human eye than a blue at 50% lightness (hsl(240, 100%, 50%)). This is because human visual perception is not uniform across the colour spectrum — we are most sensitive to green, less to red, and least to blue.

Oklch corrects for this by using a perceptually uniform model. In oklch, 50% lightness genuinely looks equally bright regardless of hue. This means:

  • Colour scales (e.g., a palette from light to dark) look evenly graduated rather than jumping at certain hues
  • Accessible contrast ratios are more predictable — colours with the same L value have similar perceived contrast
  • Gradient transitions between hues look vivid and saturated, not muddy
/* HSL gradient — turns muddy through grey */
background: linear-gradient(to right, hsl(0, 80%, 55%), hsl(270, 80%, 55%));

/* oklch gradient — stays vivid throughout */
background: linear-gradient(in oklch to right, oklch(55% 0.2 0), oklch(55% 0.2 270));

Oklch is supported in all modern browsers (Chrome 111+, Firefox 113+, Safari 16.4+). For new design systems in 2024 and beyond, oklch is the recommended format for colour scales, though you may still need HEX or RGB fallbacks for older browser support depending on your audience.

Try It Free — No Signup Required

Convert any CSS colour between HEX, RGB, HSL, and more — instantly, all in your browser.

Open Color Converter