Colour in web pages

Valid HTML 4.0!
Fight for your right to standards!
Design by Dave McLaughlin


This short essay attempts to explain the use of colours on the world wide web. In particular, it deals with the challenge of designing pages to look their best on machines limited to 256 colours.


How computer colours are defined

How we perceive colours is actually very complicated, and is a significant specialisation in psychology. Photographers recognise this, and know that different kinds of film need to be used outdoors ("daylight balanced") and indoors ("tungsten balanced"). No photographer I've ever asked can explain to me why a red clipboard appears to me to be the same colour indoors and out, although the spectrum of light it reflects depends so much on the spectrum that illuminates it. In fact, I can't explain it either, so I won't try.

Forget about why it works, here's how it works, at least in the context of a computer screen. A computer screen can really only show three colours: red, green and blue (RGB for short). Any other colour you perceive is actually a mixture of varying proportions of those three. In what follows, I'll talk about colours "displayed" by computers: bear in mind, they're always mixtures of those three components.


The Netscape websafe palette

The number of colours that can be displayed by a typical computer screen has grown over the years. Many computers nowadays can simultaneously display 65536 or more; but some are limited to 256. I believe that most web pages should be designed with the 256-colour visitor in mind.

Notice I said "simultaneously". Most computers can display a wide range of colours but some, to conserve memory, define a "palette" of 256 colours for use at any one time. Once this is defined, the colour of any one pixel can be specified by an index number from 1 to 256 (actually from 0 to 255), rather than having to list the RGB components separately.

If your screen is limited to 256 colours, you might occasionally load an image in a window, only to find that other windows change colour, often with disturbing results. That's because the new image has reassigned the palette: it uses a particular shade of lime green that wasn't previously in the palette, so it's stolen a palette index to represent that colour. Unfortunately, every other pixel on the screen with that index has become lime green, and the Mona Lisa's smile has suddenly become all the more enigmatic. If your screen is limited to 256 colours, you may find this effect unpleasant: if you design web pages, you should be wary of inflicting it on your visitors.

For many years ("many" being a relative term in this business), Netscape produced far and away the world's most popular web browser. They had their own standard palette for use on 256-colour machines and, because of their market dominance, it became the de facto industry standard.

The Netscape colour palette is based around the assumption that colours displayed on a computer screen can contain red, green and blue components each in the range 0 to 255. If the three components (R, G, B) are (0, 0, 0), the result is black; (R, G, B) = (255, 255, 255) gives white. (255, 0, 0) is a bright red, (0, 255, 0) a bright green and (0, 0, 255) a bright blue.

More subtle colours are obtained by mixing different proportions of the three primary colours. With three components, each with 256 different values to choose from, the total number of colours available is (256 x 256 x 256), or 16,777,216 (often called "16.8 million").

The Netscape colour palette is based around the (rather fortuitous) fact that 255 is 5 x 51. If the red, green and blue components are constrained to take values that are multiples of 51 (or 0), each can have six different values: 0, 51, 102, 153, 204 or 255. With six possibilities for each of the three components, the number of colours available is (6 x 6 x 6), or 216. This, conveniently, gives web page designers the majority of a 256-colour palette to play with, while leaving a few colours at the disposal of the operating system of the visitor.


Hexadecimal numbers

When designing graphics in a painting program, you can choose your colours by defining RGB components in good old decimal numbers. In HTML, however, you have to grapple with the (for many people) alien concept of hexadecimal numbers. These are not "codes", they are numbers - just represented in an unfamiliar way. An example might be <BODY BGCOLOR="#99FF99">, or <BODY BGCOLOR=#FFFFFF LINK=#00CCCC ALINK=#FF0000 VLINK=#FFFFCC>. Just what do these weird combinations of digits and letters mean?

Hexadecimal numbers seem daunting at first, but in fact learning about them is no more conceptually difficult than when you first learned about the number system with which we are all familiar. If you can cope with the idea of counting 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, etc., all you need to grasp is that there is nothing special about the number "ten".

Early in life, we all get taught that numbers go from 0 to 9, then the "tens digit" appears. The "units digit" then repeats the sequence from 0 to 9, then the "tens digit" increases to 2. The process repeats up to 99, and the "hundreds digit" introduces itself. This mechanism is truly one of the greatest inventions of humankind, but it instils in us the belief that the number ten is magic in some way, which it is not. If we each had eight fingers, we might now count 1, 2, 3, 4, 5, 6, 7, 10, 11, 12, etc., and consider that to be obviously right.

The number ten is known as the base of our everyday, or decimal number system. Other bases in common use, particularly in association with computers, are two (binary), eight (octal) and sixteen (hexadecimal).

To explain these, I'd first like to review the decimal system, and point out some features of it that we all tend to take for granted. Take a decimal number, 1234, for instance. That represents one thousand, plus two hundreds, plus three tens, plus four ones (units). Reading from right to left, we begin with units, then tens (the base of the number system. The next digit represents hundreds because one hundred is ten times ten. The next digit is thousands (ten times ten times ten). For larger numbers, this can be extended, literally if not practicably, ad infinitum.

Octal numbers are very similar to decimal numbers, except that where decimal digits represent, from right to left, increasing powers of ten, octal digits represent increasing powers of eight. Here, as elsewhere in this page, the language can be confusing, since the word "digit" itself carries connotations of the number ten.

Now consider the octal number 1234. From right to left, this represents four units, plus three eights, plus two times eight times eight, plus one time eight times eight times eight. This is where the language becomes very confusing. Notice I said "eight times eight": that's sixty-four, isn't it? Yes, but the names we assign to numbers are a consequence of their representation in the decimal system. 64 (decimal) is the same as 100 (octal). So what should we call it? People familiar with the octal system might well say "one hundred octal" or even "one hundred" (if the listener could be expected to know that the number was octal). To avoid ambiguity, it is safer to say "one zero zero octal".

The table on the right shows a few numbers in decimal and octal representations.


Notice that the digits "8" and "9" are not used in the octal system. Because the base of the system is the number eight, only eight different digits are used to represent any number.

I started with the octal system, because it is relatively easy to grasp. This next section is not essential to an understanding of hexadecimal numbers, but it does help to understand why octal and hexadecimal systems are so often used in the computer world.

The octal system shows that we don't need ten different digits to represent all possible numbers - eight will do. So, can we get away with even fewer? Yes, and most importantly (because it is the basis of all digital computers), we can use only two, in the binary system.

Computer memory is made up of lots and lots of switches. Each switch can have one of two states: on or off. These are taken to represent the digits 0 and 1. As you've seen, the base ten number system requires ten different digits, and base eight requires eight. Base two requires only two, 0 and 1. In fact, in base two, they are no longer called "digits" but "bits", for "binary digits".

In the binary system, the bits represent, from right to left, units, twos, fours, eights, etc. A binary number might look like 1111101000. Only two different digits, but a lot of them! Reading from right to left, that's no units, no 2s, no 4s, one 8, no 16s (forgive me for using decimal here, but I'm sure you don't want to go on reading "two times two times two times …"), one 32, one 64, one 128, one 256 and one 512. Add them up and, voila: one thousand (decimal). Yes, it takes no fewer than ten bits to represent even the smallest 4-digit decimal number. Binary may only use two different symbols, but it uses an awful lot of them, and is very difficult to read. On the right are a few comparisons.


So binary numbers are cumbersome and difficult to read (but essential for computers). How do people who have to deal with computers (at a low level) cope with binary numbers? The answer is that they don't directly; they convert them to another, more compact, number base. Converting between binary and decimal is tricky: that's why they use octal and hexadecimal!

Take a look at the binary representation of 1000 (decimal). To convert it to decimal, you have to recognise that it represents 512 + 256 + 128 + 64 + 32 + 8 = 1000 - that's clumsy. Because eight is itself a power of two, however, it's relatively easy to convert the same number to octal. Since eight is equal to two times two times two, a binary number can be partitioned (from right to left) in groups of three bits, and each group individually converted to an octal digit. Thus [00]1 | 111 | 101 | 000 becomes 1|7|5|0, becomes 1750 octal.

The octal system is quite good at reducing binary numbers to something less cumbersome, but it has one slight drawback. The bits in computers are usually grouped together in multiples of eight (bytes), which themselves are usually clumped in words of two or more bytes. Take that last number in the table above, 65535 (decimal) or 11111111 11111111 (binary). Convert that to octal, and you get 177777. This is sixteen bits, or two bytes. But what is the value of the first byte, and what is the second? In this case it's easy, because all the bits are 1. In any case, it's easy to partition the binary into two bytes, but what about the octal? The problem is that one of the octal digits (the third "7" in this case) contains the last bit of the first byte and the first two bits of the second byte. This kind of problem is bound to arise if you take groups of eight bits and start partitioning them into groups of three, because eight is not divisible by three. Wouldn't it be better if we had a number system where each digit represented four bits, rather than three? There is: it's hexadecimal.

Hexadecimal is base sixteen. Conversion between binary and hexadecimal is easy, like conversion between binary and octal, because the binary numbers can be partitioned into groups, each of which represents a hexadecimal digit. It's better than octal, in that each of those groups contains four bits, rather than three, and so will always line up with "byte boundaries" every eight bits.

But there's a problem in writing hexadecimal numbers. Remember that the decimal system requires ten different digits: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9. Octal, being base eight uses only the first eight of those, and binary only the first two. The hexadecimal system needs sixteen different digits. The first ten are obvious: they are the same as the familiar decimal ones; but what are we to use for the last six? Easy: just turn to the alphabet. Look at the table on the right.


Here, I've added all the leading zeroes, so you can see that every possible permutation of four bits can be represented by a single hexadecimal digit.

How does all this relate to colours on a web page? Read on.


Specifying colours in HTML

In all those HTML tags where colours are represented in the form "#RRGGBB", the "#" prefix simply signifies that what follows is a hexadecimal number. The first two digits represent the red component in the range 0 to FF (hexadecimal) or 0 to 255 (decimal); the next two are the green component, and the last two the blue.


Choosing the right colour

Even with all this background, it's not obvious what a given combination of red, green and blue components will look like. To help with this, I've written the following Java applet. It's very rough around the edges, and I gave up trying to improve it when I learned that Java security would not allow an applet like this to copy to the clipboard. Still, I'd welcome any comments.


A Microsoft Windows version of this is also available for you to download (299 kB). This is rather more mature than the Java version.