ByteTips.

Guide

HEX to RGB: How the Conversion Actually Works

A hex color is just three base-16 numbers for red, green, and blue. Split it into pairs, convert each pair to decimal, and you have RGB — plus the shorthand and alpha traps.

October 17, 2026 · 5 min read · Shayan

Short answer: a hex color like #FF5733 is three numbers written in base 16 — FF red, 57 green, 33 blue. Split the hex into pairs, convert each pair from hexadecimal to decimal (0–255), and you get rgb(255, 87, 51). Same color, different notation. Everything else on this page is detail around that one idea.

The 30-second conversion

Take #FF5733 and split it after the #: FF | 57 | 33. Each pair is a hexadecimal number — two base-16 digits. Convert each pair with (first digit × 16) + second digit, where A=10 through F=15:

  • FF → 15 × 16 + 15 = 255 (red)
  • 57 → 5 × 16 + 7 = 87 (green)
  • 33 → 3 × 16 + 3 = 51 (blue)

So #FF5733 is rgb(255, 87, 51). In code, the whole thing is six lines:

function hexToRgb(hex) {
  hex = hex.replace("#", "");
  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 };
}
hexToRgb("#FF5733"); // { r: 255, g: 87, b: 51 }

function rgbToHex(r, g, b) {
  return "#" + [r, g, b].map((x) => x.toString(16).padStart(2, "0")).join("");
}
rgbToHex(255, 87, 51); // "#ff5733"

Shorthand and alpha: the two variants

Three-digit hex like #F00 is shorthand — each digit is doubled, so #F00 means #FF0000 (pure red). Eight-digit hex like #FF573380 adds an alpha channel as the last pair: 00 is fully transparent, FF is fully opaque. To get the CSS 0–1 alpha, divide by 255 — 80 hex is 128 decimal, so #FF573380 is rgba(255, 87, 51, 0.5).

// Expand 3-digit shorthand first
function expand(hex) {
  hex = hex.replace("#", "");
  return hex.length === 3 ? hex.split("").map((c) => c + c).join("") : hex;
}
expand("F00"); // "FF0000"

// 8-digit hex → rgba()
const alpha = parseInt("80", 16) / 255; // 0.5019…
"rgba(255, 87, 51, " + alpha.toFixed(2) + ")"; // "rgba(255, 87, 51, 0.50)"

The traps

  • parseInt without a radix: parseInt("FF") returns NaN, because without the second argument it parses as decimal. Always write parseInt(pair, 16).
  • Forgetting the #: split "#FF5733" into pairs without removing it first and every channel shifts — all three values come out wrong.
  • Using shorthand raw: #F00 is not red=15, green=0, blue=0 — it is #FF0000. Double each digit before converting.
  • Reading alpha as 0–100: in 8-digit hex the alpha pair is 00–FF like any other channel. FF means 255/255 = 1, fully opaque. Divide by 255 for the CSS value.
  • Assuming the color changed: conversion only renames the value. If the swatch looks different after converting, the bug is in your code, not the math.

When you actually need RGB

For plain CSS, hex is fine and shorter. RGB earns its keep in three places: canvas and WebGL APIs, which hand you decimal channel arrays (getImageData returns 0–255 values); color math like blending or darkening, which is arithmetic on channels; and transparency — rgba(255, 87, 51, 0.5) works everywhere, while 8-digit hex still trips up older browsers and some design tools.

Try it

Paste any hex into the Color Converter — it shows the RGB, HSL, and a live preview instantly, all in your browser with nothing uploaded.

More guides