TechEarl

8-Digit Hex Colors: Alpha Transparency in Hex (#RRGGBBAA)

8-digit hex (#RRGGBBAA) adds an alpha channel as a hex byte, 00 transparent to FF opaque. The catch the old guides get wrong: the alpha pair is hex, not a percentage, so 50% opacity is 80, not 50.

Ishan Karunaratne⏱️ 7 min readUpdated
Share thisCopied
How 8-digit hex colors (#RRGGBBAA) and the 4-digit #RGBA shorthand encode alpha transparency as a hex byte from 00 to FF, with a percent-to-hex conversion table.

You can put transparency directly into a hex color by adding a fourth pair of digits: #RRGGBBAA. The last two characters are the alpha channel, where 00 is fully transparent and FF is fully opaque. So a half-transparent red is #FF000080, and a solid red is #FF0000FF (the same as #FF0000).

css
.overlay {
  /* opaque navy at full alpha */
  background: #1a2b4cff;
}

.scrim {
  /* black at ~50% alpha for a modal backdrop */
  background: #00000080;
}

That extra pair is the whole feature. There is also a 4-digit shorthand, #RGBA, that expands each digit by doubling it (the same rule that turns #f00 into #ff0000), so #f008 is #ff000088.

The mistake to avoid: the alpha is hex, not a percent

Here is the thing every older write-up on this gets wrong, including the comments correcting them: the alpha pair is a hexadecimal byte from 00 to FF, not a percentage. It is the exact same kind of number as the RR, GG, and BB pairs in front of it. Writing #FF000050 does not give you 50% opacity. 50 in hex is 80 in decimal, which is 80/255, roughly 31%.

The confusion comes from 80. Half-opacity happens to land near 80 hex because 0x80 is 128, and 128/255 is about 50.2%. So #FF000080 really is approximately 50%, but that is arithmetic, not the digits 50 meaning "50%." If you want a clean mental model: an alpha byte of FF (255) is 100%, 00 is 0%, and everything in between is value / 255.

Converting a percentage to a hex alpha byte

The conversion is: alphaByte = round(opacity × 255), then write that as two hex digits.

css
/* 75% opacity:  0.75 × 255 = 191.25 → 191 → BF */
.panel { background: #2196f3bf; }

You almost never need to do this by hand. Here are the values people reach for most:

OpacityDecimal (× 255)Hex alpha
100%255FF
90%230E6
75%191BF
50%12880
25%6440
10%261A
0%000

If you find yourself memorizing this table, that is usually the signal to reach for the modern syntax below instead, where you can just write the percentage.

When to use #RRGGBBAA, and when to use rgb(... / 50%)

8-digit hex is great when you already have a hex value in hand (a brand color, a token copied out of a design tool) and you want to drop alpha onto it without converting anything to rgb(). It is compact and it pastes cleanly.

But CSS Color Level 4 gave rgb() and hsl() a modern, space-separated form with a slash before the alpha, and there the alpha can be a real percentage or a 0 to 1 number:

css
.scrim-modern {
  /* same ~50% black, but the alpha is readable */
  background: rgb(0 0 0 / 50%);
}

.tint {
  background: hsl(210 100% 56% / 0.25);
}

This is the form I default to when the alpha is the point of the rule, because / 50% says exactly what it means and nobody has to know that 80 is "about half." Reach for #RRGGBBAA when you are starting from a hex string; reach for the slash syntax when readability of the alpha matters. The old comma form (rgba(0, 0, 0, 0.5)) still works everywhere and is now just a legacy alias for rgb(), so there is no reason to prefer it in new code.

One more 2026-era option: if your color lives in a CSS custom property and you want a translucent version of it, color-mix() does that without you ever touching hex math:

css
.card {
  /* 80% of the token color, 20% transparent */
  background: color-mix(in srgb, var(--brand) 80%, transparent);
}

That keeps a single source-of-truth token and derives the faded variant from it, which is cleaner than maintaining a parallel --brand-faded hex string.

Browser support

8-digit and 4-digit hex are Baseline and have been safe to ship for years: Firefox shipped it in 2016 (Firefox 49), Safari in 2016 (Safari 10), and Chrome in 2017 (Chrome 62). The old EdgeHTML engine never parsed it, but Edge inherited support when it moved to Chromium in 2020 (Edge 79), so every current browser parses #RRGGBBAA and #RGBA natively. There is nothing to prefix and no fallback to write for any browser still in use. The space-separated rgb(... / a) and hsl(... / a) slash syntax and color-mix() are likewise broadly supported across current engines. If you are matching hex values out of text (in a linter, a find-and-replace, or a form field), the pattern has to account for the 3-, 4-, 6-, and 8-digit lengths, which is its own small problem covered in matching a hex color code with regex.

See also

Sources

Authoritative references this article was fact-checked against.

Tagscsshex colorrgbatransparencyalpha channelRRGGBBAAcolor

Found this useful? Pass it on.

Copied

Ishan Karunaratne

Tech Architect · Software Engineer · AI/DevOps

Tech architect and software engineer with 20+ years building software, Linux systems, and DevOps infrastructure, and lately working AI into the stack. Currently Chief Technology Officer at a healthcare tech startup, which is where most of these field notes come from.

Keep reading

Related posts

50 VC Funding Jokes for the Pre-Revenue Era

Fifty VC funding jokes about term sheets, Tier-1 funds, the founder dinner, the down round nobody calls a down round, and the partner who liked the demo enough to follow up next quarter.

How to Archive Files Matching a find Pattern with tar

find locates the files, tar archives them. The safe pairing is find -print0 piped into tar reading a NUL-delimited list from stdin: no breakage on spaces or newlines. The flag breakdown, the macOS BSD tar vs GNU tar difference, the -exec append alternative, archiving by modification time, and the compression choices.