CS Nibbles Logo

CSS Colors in Hex

As we saw in CSS Colors Pt 1, colors in CSS are stored in 3-4 bytes with 1 byte each to represent the amount of red, green or blue present. Other than RGB notation and binary, another common way of representing colors in CSS is hex notation. For example, green in hex notation is x00ff00. A color is defined using six hex digits in total, and the amount of each primary color is defined using two hex digits. Each digit can be a number in the range of 0-f.

x ( [0-f][0-f], [0-f][0-f], [0-f][0-f] )
     │           │           └────────── blue
     │           └───────────── green
     └───────────────── red

If you're not familiar with hexadecimal, it might seem odd to talk about a range of numbers where f is the last number in the range. Just know that hexadecimal is a base-16 number system, and we need a single distinct glyph for the numbers 0-15, so we use the usual decimal digits for 0-9 and we use the letters of the alphabet to represent 10-15.

Hexadecimal Decimal
0-9 0-9
a 10
b 11
c 12
d 13
e 14
f 15

There's a special mathematical relationship between binary and hexadecimal. One hexadecimal digit can represent the exact same set of numbers as four bits. To convince yourself of this, think about the biggest number that we can represent in four bits. Then think about the biggest number that we can represent in one hex digit. Both are 15.

  1111
  (2 possible values in base-2) ** (4 digits)
= 16 total possible values, or 0-15

  f
  (16 possible values in base-16) ** (1 digit)
= 16 total possible values, or 0-15

What if we wanted to represent 1 byte as hexadecimal? Well, if we can represent 4 bits using 1 hex digit, then we can represent 8 bits using 2 hex digits.

  1111 1111
  (2 possible values in base-2) ** (8 digits)
= 256 total possible values, or 0-255

  ff
  (16 possible values in base-16) ** (2 digit)
= 256 total possible values, or 0-255

Here's another way to express the same idea above. Instead of doing (base of number system) ** (total number of digits), first we calculate that result for just four bits or 1 hex digit and then we multiply that output by itself in order to get the final answer for 1 byte.

  1111 1111
  ((2 possible values in base-2) ** (4 digits)) ** 2
= 16 * 16
= 256 total possible values, or 0-255

  ff
  ((16 possible values in base-16) ** (1 digit)) ** 2
= 16 * 16
= 256 total possible values, or 0-255

Now you know why it takes two hex digits to represent how much red, green, or blue is present in a color. Since it takes 1 byte to denote each amount, we can represent the exact same value using two hexadecimal digits.

rgb ( [0-255],    [0-255],    [0-255]    )
x   ( [0-f][0-f], [0-f][0-f], [0-f][0-f] )
       │           │           └────────── blue
       │           └───────────── green
       └───────────────── red

You'll see hexadecimal over and over again in computing, because it's way more compact and human-readable than binary, which was never really meant to be read by anyone other than computers anyway. Indeed, whenever you wish to inspect the raw binary of something, you're more likely than not going to see it displayed in hex format.

Note: If you've never used the command-line utilities xxd or hexdump before, now is a good time to explore by typing man xxd or man hexdump in your terminal.

Practice It On Your Own