← Back to Blog
CSSWeb DesignColor TheoryFrontend Development

Color Formats: HEX, RGB, and HSL Explained

A color format is a notation system that describes a specific color using numbers, letters, or a combination of both. HEX, RGB, and HSL are the three formats you'll use in almost every CSS file, design handoff, and brand guideline you touch.

This post breaks down how each format works, when one is a better pick than the others, and how to convert between them without memorizing formulas. If you've ever stared at #3B82F6 and wondered what color that actually is, this is for you.

How does HEX color notation work?

HEX is a six-character code that represents a color using hexadecimal (base-16) values. Each pair of characters maps to red, green, and blue intensity on a scale from 00 (none) to FF (full). The format always starts with a #.

Take #3B82F6 — that's Tailwind's blue-500. Breaking it down:

  • 3B → Red: 59 (out of 255)
  • 82 → Green: 130
  • F6 → Blue: 246

So it's a color with very little red, moderate green, and almost full blue. Makes sense — it looks blue.

CSS also accepts shorthand HEX when each pair repeats: #FFFFFF becomes #FFF, and #000000 becomes #000. You can add two more characters for alpha transparency: #3B82F680 gives you that same blue at 50% opacity.

HEX became the default in web development mostly by accident — early HTML supported it before CSS even existed, and decades of muscle memory kept it dominant. Figma, Sketch, and every browser DevTools panel default to HEX output.

The downside: it's not human-readable. Looking at #8B5CF6, you can't tell it's purple without converting it. That's where the other formats earn their spot.

What makes RGB different from HEX?

RGB describes a color using three decimal values — one each for red, green, and blue — on a scale from 0 to 255. The CSS syntax is rgb(59, 130, 246).

That's the same color as #3B82F6. The only difference is the notation: HEX uses base-16, RGB uses base-10. Your brain can parse rgb(59, 130, 246) faster because you already think in decimals.

The modern CSS spec (CSS Colors Level 4) dropped the commas and added optional alpha as a slash:

/* Old syntax — still works */
rgba(59, 130, 246, 0.5)

/* Modern syntax */
rgb(59 130 246 / 0.5)

Both are valid. The modern version is cleaner, and every browser released after 2020 supports it.

RGB shines when you're manipulating individual channels programmatically. If you need to bump the red channel by 20 to warm up a color, it's straightforward: change rgb(59, 130, 246) to rgb(79, 130, 246). Try doing that in HEX and you're reaching for a calculator.

But RGB has the same readability problem as HEX. If I hand you rgb(168, 85, 247), you don't instantly know that's a purple. You have to mentally compute that blue is high, red is medium, green is low. It's possible, but it's work.

Why do developers switch to HSL?

HSL stands for Hue, Saturation, Lightness, and it maps to how humans actually think about color. Instead of mixing three light channels, you pick a color on a wheel, decide how vivid it should be, and set how light or dark it appears.

  • Hue is a degree on the color wheel: 0° is red, 120° is green, 240° is blue, 360° wraps back to red
  • Saturation is a percentage: 0% is gray, 100% is the purest version of that hue
  • Lightness is also a percentage: 0% is black, 50% is the "normal" color, 100% is white

That Tailwind blue from before? In HSL it's hsl(217, 91%, 60%). I can read that: it's a blue-ish hue (217°), highly saturated (91%), at medium lightness (60%). No mental math needed.

Sara Soueidan wrote about switching her entire site from HEX/RGB to HSL. The reason was practical: when you need five shades of the same blue for a design system, you keep the hue and saturation constant and just slide lightness:

--blue-100: hsl(217, 91%, 90%);
--blue-300: hsl(217, 91%, 75%);
--blue-500: hsl(217, 91%, 60%);
--blue-700: hsl(217, 91%, 40%);
--blue-900: hsl(217, 91%, 25%);

Try building that scale in HEX and you'll understand why HSL is popular for design systems. Each value is predictable. You can see the pattern. Adjusting one property doesn't scramble the others.

The CSS syntax mirrors RGB's modern form:

hsl(217 91% 60%)
hsl(217 91% 60% / 0.5)  /* with alpha */

Which format should you use in CSS?

Choosing a format depends on what you're doing with the color after you write it down. There's no universally "best" format — each fits a different workflow.

Use HEX when you're copying colors from design tools, working with brand guidelines that specify hex codes, or you just want the most compact notation. Most design-to-code handoffs use HEX because that's what Figma exports.

Use RGB when you're programmatically adjusting individual color channels, working with canvas APIs like CanvasRenderingContext2D.fillStyle, or building animations that interpolate between channel values. JavaScript's getComputedStyle() returns colors in RGB format, so if you're reading colors from the DOM and modifying them, staying in RGB avoids extra conversions.

Use HSL when you're building a color scale, creating theme variations, or need to reason about color relationships. Design systems like Radix Colors and Open Props use HSL-based scales because the math is intuitive.

You can mix formats in the same stylesheet. CSS doesn't care. A common pattern is to define your palette in HSL (for easy scale generation) and then reference the resulting values however they show up in your tooling.

What about newer CSS color formats like OKLCH?

OKLCH is a color format available in CSS Colors Level 4 that fixes a long-standing problem with HSL: perceptual uniformity. In HSL, hsl(60, 100%, 50%) (yellow) looks much brighter than hsl(240, 100%, 50%) (blue) even though they have the same lightness value. Human vision doesn't perceive lightness equally across hues.

OKLCH uses a perceptually uniform color space, so lightness 0.7 actually looks the same brightness whether the hue is yellow, blue, or red. The syntax:

oklch(0.7 0.15 240)  /* lightness chroma hue */

Josh Comeau covers this well — OKLCH produces more consistent results when you generate color palettes programmatically. Tailwind CSS v4 switched its default palette to OKLCH for exactly this reason.

Browser support for OKLCH is solid in 2026: Chrome 111+, Firefox 113+, Safari 15.4+. If you're building a new project today, it's worth considering. But HEX, RGB, and HSL aren't going anywhere — they're the foundation everything else builds on, and they'll remain the most commonly used formats for years.

How do you convert between HEX, RGB, and HSL?

Converting between formats involves straightforward math, but you don't need to do it by hand. Here's how the conversions work conceptually, and then the fast way to actually do them.

HEX → RGB is the simplest. Split the hex string into pairs and convert each from base-16 to base-10. #3B82F63B = 59, 82 = 130, F6 = 246 → rgb(59, 130, 246).

RGB → HSL requires a bit more math. You normalize the RGB values to 0–1, find the min and max, derive lightness from their average, saturation from the difference, and hue from which channel is dominant. The CSS spec has the full algorithm.

In JavaScript, here's a minimal RGB-to-HSL function:

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 [Math.round(h * 360), Math.round(s * 100), Math.round(l * 100)];
}

rgbToHsl(59, 130, 246); // [217, 91, 60]

Or skip the math entirely and use a color converter tool — paste any format and get all the others instantly.

Quick reference

Format Syntax Best for Readability Browser support
HEX #3B82F6 Design handoffs, compact notation Low — not human-parseable All browsers since the 1990s
RGB rgb(59, 130, 246) Channel manipulation, canvas APIs, JS interop Medium — decimal values help All browsers
HSL hsl(217, 91%, 60%) Color scales, theming, design systems High — maps to human perception IE9+ (2011 onward)
OKLCH oklch(0.7 0.15 240) Perceptually uniform palettes High — true lightness consistency Chrome 111+, Firefox 113+, Safari 15.4+

Common conversions for reference:

Color HEX RGB HSL
White #FFFFFF rgb(255, 255, 255) hsl(0, 0%, 100%)
Black #000000 rgb(0, 0, 0) hsl(0, 0%, 0%)
Red #FF0000 rgb(255, 0, 0) hsl(0, 100%, 50%)
Tailwind blue-500 #3B82F6 rgb(59, 130, 246) hsl(217, 91%, 60%)
Tailwind green-500 #22C55E rgb(34, 197, 94) hsl(142, 71%, 45%)

Pick the format that matches your workflow: HSL for design systems, HEX for Figma handoffs, RGB for channel manipulation in code. Need to convert between them? The color converter handles all formats instantly.

Try the tool mentioned in this article:

Open Tool →