Hex opacity is the two-digit alpha value appended to a standard 6-digit hex color code, turning #RRGGBB into #RRGGBBAA. The last two characters control transparency: 00 is fully transparent, FF is fully opaque, and everything between is a partial level of transparency.
To get a transparent hex code for any color, find the opacity percentage in the table below and append it to your hex color. Red (#FF0000) at 50% opacity becomes #FF000080. For a fully transparent hex code, use any color followed by 00, such as #00000000.
Using Hex Opacity in CSS
You can apply hex opacity to any CSS property that accepts a color value: backgrounds, borders, text, box shadows, and more. Just append the two-digit hex value to any existing color code.
/* Background with 50% opacity */
background-color: #0000FF80;
/* Text color at 70% opacity */
color: #333333B3;
/* Border at 25% opacity */
border: 1px solid #FF000040;
/* Box shadow with transparency */
box-shadow: 0 4px 6px #00000033;
CSS also supports a 4-digit shorthand format (#RGBA), where each digit is doubled. So #0F08 is the same as #00FF0088. This shorthand only works when each pair of digits is identical, so it’s less commonly used than the full 8-digit format.
One platform difference worth knowing: Android and Kotlin use the reversed format #AARRGGBB, where the alpha comes first. The table below still applies for the alpha portion; just swap its position when writing Android color values.
Hex Opacity Table
Here is a handy table to quickly find the opacity hex code to append to your hex color.
For example, to get 95% opacity, append F2 to your hex color. Red at 95% opacity: #ff0000f2.
The hex values use standard mathematical rounding (rounding 0.5 up). So 50% maps to 80 (128 in decimal, since 127.5 rounds up) rather than 7F (127). Some tools use truncation instead and show 7F for 50% and 3F for 25%. Both are valid CSS values. The visual difference is imperceptible.
| Opacity Value (%) | Hex Code |
|---|---|
| 100 | FF |
| 99 | FC |
| 98 | FA |
| 97 | F7 |
| 96 | F5 |
| 95 | F2 |
| 94 | F0 |
| 93 | ED |
| 92 | EB |
| 91 | E8 |
| 90 | E6 |
| 89 | E3 |
| 88 | E0 |
| 87 | DE |
| 86 | DB |
| 85 | D9 |
| 84 | D6 |
| 83 | D4 |
| 82 | D1 |
| 81 | CF |
| 80 | CC |
| 79 | C9 |
| 78 | C7 |
| 77 | C4 |
| 76 | C2 |
| 75 | BF |
| 74 | BD |
| 73 | BA |
| 72 | B8 |
| 71 | B5 |
| 70 | B3 |
| 69 | B0 |
| 68 | AD |
| 67 | AB |
| 66 | A8 |
| 65 | A6 |
| 64 | A3 |
| 63 | A1 |
| 62 | 9E |
| 61 | 9C |
| 60 | 99 |
| 59 | 96 |
| 58 | 94 |
| 57 | 91 |
| 56 | 8F |
| 55 | 8C |
| 54 | 8A |
| 53 | 87 |
| 52 | 85 |
| 51 | 82 |
| 50 | 80 |
| 49 | 7D |
| 48 | 7A |
| 47 | 78 |
| 46 | 75 |
| 45 | 73 |
| 44 | 70 |
| 43 | 6E |
| 42 | 6B |
| 41 | 69 |
| 40 | 66 |
| 39 | 63 |
| 38 | 61 |
| 37 | 5E |
| 36 | 5C |
| 35 | 59 |
| 34 | 57 |
| 33 | 54 |
| 32 | 52 |
| 31 | 4F |
| 30 | 4D |
| 29 | 4A |
| 28 | 47 |
| 27 | 45 |
| 26 | 42 |
| 25 | 40 |
| 24 | 3D |
| 23 | 3B |
| 22 | 38 |
| 21 | 36 |
| 20 | 33 |
| 19 | 30 |
| 18 | 2E |
| 17 | 2B |
| 16 | 29 |
| 15 | 26 |
| 14 | 24 |
| 13 | 21 |
| 12 | 1F |
| 11 | 1C |
| 10 | 1A |
| 9 | 17 |
| 8 | 14 |
| 7 | 12 |
| 6 | 0F |
| 5 | 0D |
| 4 | 0A |
| 3 | 08 |
| 2 | 05 |
| 1 | 03 |
| 0 | 00 |
Hex Opacity vs. rgba() and the opacity Property
Three CSS approaches handle color transparency. They’re not interchangeable.
#RRGGBBAA hex notation applies transparency to a single color value. It works anywhere a color is accepted in CSS. The downside is readability: #FF000080 isn’t as clear as rgba(255, 0, 0, 0.5) at a glance.
rgba() and hsla() are the more readable alternatives. The alpha channel uses a 0-1 decimal (0.5 for 50%), so no hex conversion is needed. Both rgba() and 8-digit hex produce identical results; they’re different syntax for the same thing.
Modern CSS has two more options worth knowing. The space-separated rgb() syntax takes alpha after a slash and accepts a percentage, so there’s no separate rgba() function to remember. And color-mix() can fade any color, including a CSS variable, toward transparent without you ever working out a hex value.
/* Same result as #FF000080 */
background-color: rgb(255 0 0 / 50%);
/* Fade a variable to 50% without knowing its hex value */
background-color: color-mix(in srgb, var(--brand) 50%, transparent);
The slash syntax works in Chrome 65, Firefox 52, and Safari 12.1 and later. color-mix() needs Chrome 111, Firefox 113, or Safari 16.2. color-mix() is the better fit when your colors live in design tokens, since you can’t append 80 to a variable.
The CSS opacity property works differently. Setting opacity: 0.5 on an element makes the entire element transparent, including its children. Text inside a semi-transparent container will inherit the parent’s opacity. To keep text fully visible while making only the background transparent, use background-color with hex opacity or rgba() instead.
/* These produce identical results */
background-color: #FF000080;
background-color: rgba(255, 0, 0, 0.5);
/* This makes the entire element AND its children 50% transparent */
opacity: 0.5;
Understanding the Hexadecimal System
Decimal is base 10: digits run from 0 to 9. Hexadecimal is base 16, so it adds six more symbols: A, B, C, D, E, and F. That gives each digit position 16 possible values instead of 10.
A single hex digit represents values from 0 to F, where F equals 15 in decimal. Two hex digits together cover 0 to 255 (FF in hex). That range is why the opacity channel fits in exactly two characters.
Valid two-digit hex values include 00, 01, 99, 9D, CC, E4, and F5. Letters are case-insensitive in CSS, so #ff0000f2 and #FF0000F2 are the same color.
Browser Support
8-digit hex color notation is well-supported across all modern browsers. CSS #RRGGBBAA notation shipped in Safari 10 and Firefox 49 in September 2016, then Chrome 62 in October 2017. Edge picked it up in January 2020 with version 79, its first Chromium-based release; the older EdgeHTML versions never supported it. Internet Explorer never did either, so use rgba() if you still have to support it.
I know I am being a bit nit-picky but should 25% not be 3F,
50% be 7F, and 100% be FF?
The issue is the percentages are based on 1-100 whereas the hex values are zero based from 00 to FF. We cannot have hex 100 which would be 3 digits where only 2 digits are allowed – you could do that with HSL(degrees, saturation %, luminosity %) but not with #FFFFFF2F, for example.
In the grand scope of things it doesn’t really matter, I suppose and most people are really only going to use 25%, 50%, and 75%.