Weird right? 4-digit hex codes too. They are a way put alpha transparency information into the hex format for colors. You might be seeing it more all the sudden if you use Chrome, because it dropped in 52, and the DevTools seem to be defaulting to showing alpha transparent colors in this format even if you set it originally using something else.
Firefox supports it too, for the record.
Let’s look at how it works:
.element {
/* This is green */
background: rgb(0, 255, 0);
/* It's the same as this */
background: #00ff00;
/* We could make it 50% transparent like this */
background: rgba(0, 255, 0, 0.5);
/* Or, with an alpha hex like this */
background: #00ff0080;
}
Those last two digits represent the alpha transparency. But wait… the last two digits are “80”, not “50”. We’ll get to that.
First, remember how three digit hexes work?
.element {
/* This */
background: #900;
/* Is the same as this */
background: #990000;
}
It’s each digit doubled up. It’s the same way with four digits.
.element {
/* This */
background: #0f08;
/* Is the same as this */
background: #00ff0088;
}
The formats are sometimes referred to as #RRGGBBAA and #RGBA.
The AA part is a hex representation of 0-100 is like:
0 = 00
1 = 03
2 = 05
…
9 = 17
…
10 = 1A
11 = 1C
12 = 1F
…
99 = FC
100 = FF
That’s why “80” was really “50% transparency” in the example up top.
Also, here’s a chart that I adapted from here:
See the Pen XjbzAW by Chris Coyier (@chriscoyier) on CodePen.
Should you use it?
Probably not. It’s not very well supported yet and doesn’t have any advantages over rgba()
or hsla()
, other than, I suppose, a tiny amount of saved bytes.
I really don’t get your series. 10 = 1A? 11 = 1C? 12 = 1F? What?! You’re mixing up the 0% – 100% with the 0 – 255 values. If you do a series with 0 – 255, the hexadecimal values you posted are nonsense. If you do a 0% – 100% series, then the series it’s nonsense as well as you don’t have numbers bigger than 100%.
It certainly is a bit confusing. I think it might be rooted in that you need to represent both 0 and 100 with just 2 digits. If it were integers only, there isn’t a good way to do that.
00
could be0
, but you can really only go up to99
from there. So might as well use the same system as the other numbers use I suppose.No, Chris, it’s not that confusing. Your series is just wrong.
I find your comment extremely rude.
I do find it confusing. I didn’t realize that hex values are different depending on the scale they are representing.
On the 255 scale, 10 is 0A
On the 100 scale, 10 is 1A
Making these sets equivalent:
I think that’s correct, but as I’m rather new to this concept, I’m sure I could still be wrong.
Chris,
Rudeness aside, I think Aaron is right you may have read the chart wrong and misunderstood this.
The alpha is not an integer percentage, but a decimal value from 0 to 1. This is mapped onto 256 possible values. 50% opacity is 80 because that is 128 decimal which is half of 256.
If you look at your generated sequence, you’ll see that it gives you values different than you quoted:
0% 00
1% 03
2% 05
…
9% 17
So your initial sequence, before it gets weird, is off by almost half.
Turn the math on its head. For each hex value from 00 to ff, what alpha value are you writing:
Its a little different because of how the rounding is happening but I think that shows what you’re doing much more clearly (I don’t think my math is off).
Oops! forgot to login when I did that. The preview just showed the link which suckered me into missing it.
I think it is all a misunderstanding, what Chris is getting at is:
1% transparency is represented by the hex “03”, 9% by “23”, 12% by “1F”, 100% by “FF”.
You know what’s really frustrating about this? Internet Explorer had 8-digit hex codes. But they’re not in #RRGGBBAA. They’re in #AARRGGBB. Which is pronounced “Argh!” if you think about it too much. ;)
I think Microsoft made a bad choice back then (along with all the legacy
filter
thing) putting the alpha channel before the RGB, but was right in using a hex syntax for it. But then again, we havergba
as color function, notargb
, so it’s only natural to stick with#rrggbbaa
.It’s also entirely possible that the W3C chose to put the alpha at the end out of spite of Microsoft. Wouldn’t have been the first time.
I think you’ve got an oops in your explanation of hex:
11d == 0x1B and 12d == 0x1C, not 1A and 1F as you’ve got written.
The hex conversions are mixed up. It looks like some of them are decimal and some are percent.
0 = 00 (decimal and percent)
1 = 01 (decimal)
2 = 02 (decimal)
…
9 = 09 (decimal)
10 = 1A (percent)
… then it starts to get weird …
11 = 1C (percent)
12 = 1F (percent)
… whatever, someone figured it out and it works …
254 = FE (decimal)
255 = FF (decimal)
Looking better now. The only outstanding issue is 9 = 23 should be 9 = 17 according to the codepen. 23 is the number value. 17 is the hex value.
You meant:
That’s how Hex actually work: you count 0 to F , as in 0,1,..8,9,A,B,..F
Looks like this is 100% true when representing 0-255 in hex, but the scale for 0-100 in hex is different.
Chris,
it looks like the first numbers in your example are wrong.
it shoud be:
http://stackoverflow.com/questions/5445085/understanding-colors-in-android-6-characters/25170174#25170174
The confusion is that it’s using hex values to represent a % from 1-100. So hex 1A is 26 in decimal, 26 / 255 = ~ 10%. That’s why 1A is 10.
There’s nothing complicated or weird at all, just basic math and hex conversion. Just the same way we use other RGB color components in hex notation. You are overcomplicating it Chris ;)
var range = 256; // 0 to 255 or 16*16 or FF
var alphaLevel = 1/2; // 50% so 50/100
var x = Math.round(range * alphaLevel); // simple rounding to remove floating point from number
x.toString(16);
Binary is why it makes sense.
What Adrian said.
To keep it simple, just like the hex colors it’s a ratio 00/00 is black, 88/FF is half of whatever color, and FF/FF is full color. The same goes for alpha.
Roughly…
00 (hex) = 00/FF (hex) = 0/255 (dec) = 0% alpha
40 (hex) = 40/FF (hex) = 64/255 (dec) = 25% alpha
80 (hex) = 80/FF (hex) = 128/255 (dec) = 50% alpha
C0 (hex) = C0/FF (hex) = 192/255 (dec) = 75% alpha
FF (hex) = FF/FF (hex) = 255/255 (dec) = 100% alpha
You can replace “alpha’ with R, G, or B. It works the same.
Your table needs updating — I marked the numbers on the left as (decimal) percentages, changed the values of the hex numbers on the right, and marked the numbers explicitly “hex”:
0% = 00 (hex)
1% = 03 (hex)
2% = 05 (hex)
3% = 08 (hex)
4% = 0A (hex)
5% = 0D (hex)
…
9% = 17 (hex)
~~… then it starts to get weird …~~
10% = 1A (hex)
11% = 1C
12% = 1F
…
99% = FC (hex)
100% = FF (hex)
I just wanted to say that I absolutely love all the in depth articles on css-tricks and it’s a wonderful, super informative web site. I use many css-tricks articles as my go-to reference!
I hope my comments about hex colors are helpful.
Given the comments so far I think we’ve found a great reason not to bother with 4/8 hex codes, seriously :). There probably in’t a single good use case for them against RGBA, HSLA. Unless you’re a hex wizard they’re completely unintuitive, but still as always with css-tricks it nice read about something you don’t often come across.
They may be useful for tool generators. If you’re processing CSS, it doesn’t really need to be in a human readable form anyhow. It’s just one less step to have a compiler to make. Also an automated tool that reads a CSS file could simply look for a pattern using hex codes and add in an opacity without actually altering a hex code.
So, in short, like MOST applications of hexadecimal, more useful for machines than people. In fact, let’s be honest, even RGB is probably not as good as HSLA for many people as once you’ve decided on your site’s main hues, most of the changes you’re going to make is to how saturated or washed out that hue is. But HSLA vs. RGBA is a different conversation.
Using hex codes for opacity has everything to do with it being stored as a binary value.
That value is converted into a percentage in real-world terms, but essentially it just offers you 256 levels of opacity, just like photoshop. In case you were wondering, every graphics program also has the ability to have 256 levels as well ( 0–255 ) and everything in between would be a percentage of that.
Essentially, you can think of it as:
So 0–100% in rgba effectively translates into a value between 0 and 255 (decimal) anyway. The reason is because the underlying storage is 8 bits, so you have 256 levels to use up anyhow.
0–255 ( Base 10 )
00–FF ( Base 16 )
0000 0000 – 1111 1111 ( Base 2 )
You can see the progression of the digits below.
In the end, storing things in hex is probably only really useful when your colors are being autogenerated by a tool. It’s actually less work to keep it in Base 16 than convert back and forth from a decimal in Base 10 ( which, by the way, is still storing it in binary in the end )
I usually love your stuff here Chris but you’re explanation of the scale is wrong and you could easily confuse people who don’t know hex that well.
The other comments explain the actual series fine but I think the larger point to make here is that you’re not representing 0-100 in hex (which would be 0-64), you’ve just stretched the scale (50 is half of 100, 128 is half of 256, both are 50% of the maximum) and then changed the way you write the number (128 in decimal is 80 in hex so 80 gives you 50% in 8 digit hex), what is important is the fraction of your value to the maximum.
Really the biggest mistake was going for a 0-100 scale for alpha in rgba() rather than the same 1-255 scale as the other channels.
Without trying to sound rude, this is article is a perfect example of why I think front-end developers should dabble with programming outside of what happens in a web browser. For example, write a standalone program that inverts an image. You’ll learn all about image formats, color formats (24-bit, 32-bit, 64-bit, RGB, RGBA, ABGR, ARGB, and more, some with uneven component sizes!), byte-level color and pixel manipulation, and more. In my years of front-end development, I’ve found that a foundation in general graphics programming has helped me immensely.
And once you do that, you’ll be happy you’ll never have to deal with formats like R5G6B5 (16-bit RGB) or R5G5B5A1 (16-bit RGBA) ever again ;)
There is a way hot to use it even today. With postCSS plugin: https://github.com/postcss/postcss-color-hex-alpha