HEX vs RGB vs HSL — Color Formats Explained for Developers

#1e90ff, rgb(30, 144, 255), and hsl(210, 100%, 56%) are the exact same color written three ways. Each notation exists because it is convenient for a different audience — machines, graphics programmers, and humans respectively. Once you understand what each number means, converting between them stops being magic and choosing the right one for the job becomes obvious.

Hex Anatomy: #RRGGBB

A hex color is three numbers glued together, one per light channel, each written in base-16 (hexadecimal) using digits 0-9 and letters a-f:

#1e90ff
 ── ── ──
 R  G  B
 1e = 30    red channel   (out of ff = 255)
 90 = 144   green channel
 ff = 255   blue channel  (maxed out → a blue-leaning color)

Extremes:
#000000 = no light        = black
#ffffff = all channels max = white
#ff0000 = pure red

Two useful variants:

  • 3-digit shorthand — #f0c expands to #ff00cc by doubling each digit. Only works when all three pairs are doubles, so #1e90ff has no shorthand.
  • 8-digit alpha (#RRGGBBAA) — a fourth pair adds opacity: 00 is transparent, ff is opaque, 80 is ~50%. #1e90ff80 is our blue at half opacity. Supported in all modern browsers, with a #RGBA short form too.

Hex is compact, universally supported, and what design tools copy to your clipboard — which is why it dominates codebases. Its weakness: the numbers are opaque to humans. Quick — is #9b59b6 warm or cool? You cannot tune a hex value by eye. If you need to validate hex strings in code, see regex for hex color validation.

rgb() and rgba(): The Same Channels in Decimal

The rgb() function expresses the identical three channels as decimal numbers from 0 to 255 — no mental base-16 conversion required:

rgb(30, 144, 255)          /* same color as #1e90ff */
rgba(30, 144, 255, 0.5)    /* legacy alpha syntax */
rgb(30 144 255 / 0.5)      /* modern space-separated syntax */

RGB is the format JavaScript gives you back from getComputedStyle and canvas pixel reads, and the natural format when a color is computed at runtime. It shares hex's weakness, though: three light intensities still do not tell a human what the color looks like or how to adjust it.

HSL: The Human Model

HSL abandons light channels and describes color the way people talk about it:

  • Hue (0-360) — the angle on the color wheel: 0 red, 60 yellow, 120 green, 180 cyan, 240 blue, 300 magenta, wrapping back to red at 360.
  • Saturation (0-100%) — color intensity: 100% is vivid, 0% is gray regardless of hue.
  • Lightness (0-100%) — 0% is always black, 100% always white, 50% is the pure color.

The payoff is that edits become predictable. Want a darker hover state? Lower L. A pastel version? Raise L, lower S. A complementary accent? Add 180 to H:

base:       hsl(210, 100%, 56%)   /* dodger blue */
hover:      hsl(210, 100%, 46%)   /* same hue, darker */
subtle bg:  hsl(210, 100%, 95%)   /* same hue, near-white */
complement: hsl(30, 100%, 56%)    /* orange, hue + 180 */

Try doing any of those with hex arithmetic. This is why designers and design systems think in HSL even when the final tokens are stored as hex.

One Color, All Three Ways

Let us walk dodger blue through every notation to see the equivalences:

HEX:  #1e90ff
      1e → 30, 90 → 144, ff → 255

RGB:  rgb(30, 144, 255)
      blue is the max channel → hue lands in the blue region

HSL:  hsl(210, 100%, 56%)
      hue 210°  = between cyan (180°) and blue (240°)
      sat 100%  = the max and min channels are far apart (255 vs 30)
      light 56% = (max + min) / 2 / 255 = (255+30)/510 ≈ 0.56

With 50% opacity:
      #1e90ff80 = rgb(30 144 255 / 0.5) = hsl(210 100% 56% / 0.5)

Same pixel on screen in every case. The conversion algorithms are a dozen lines of JavaScript each — we walk through working code in convert colors in JavaScript.

Who Prefers Which — and What's Next

  • Hex — design handoffs, stored tokens, quick copy-paste. The lingua franca.
  • RGB — JavaScript interop, canvas work, anything computing channel values.
  • HSL — building palettes, hover/focus variants, theming systems where colors are derived rather than hand-picked.

One paragraph on the future: modern CSS has grown beyond sRGB. The oklch() function describes colors by perceptual lightness, chroma, and hue — fixing HSL's quirk where 50% lightness yellow looks far brighter than 50% lightness blue — and the P3 color space unlocks more vivid colors on modern displays. The mental model you built here transfers directly: oklch is "HSL, but perceptually honest". For day-to-day work, hex, rgb(), and hsl() remain everywhere and are what tools and teams expect.

Frequently Asked Questions

What is the difference between HEX, RGB, and HSL?

All three describe the same colors. HEX and RGB encode the red, green, and blue light channels — HEX as base-16 pairs (#1e90ff), RGB as decimal values (rgb(30, 144, 255)). HSL instead describes hue (angle on the color wheel), saturation, and lightness, which matches how humans reason about color.

When should I use HSL instead of HEX?

Use HSL when you need to derive variations: a hover state 10% darker, a pastel version at lower saturation, or a palette of shades from one hue. Adjusting one HSL number makes predictable changes, while editing hex digits does not.

What does the 8-digit hex format #RRGGBBAA mean?

The last two digits are an alpha (opacity) channel from 00 (fully transparent) to FF (fully opaque). For example, #1e90ff80 is the dodger blue color at roughly 50% opacity. All modern browsers support 4- and 8-digit hex with alpha.

Try the Free Color Converter

Convert HEX ↔ RGB ↔ HSL instantly, right in your browser. No signup, no cost.

Related articles