The Computer Science Behind Colour

Hayley van Waas | August 2021

A lot of people struggle with confidence when they start learning how to use a new tool on their computer, or start programming. So many people have this idea that computers are these magical all knowing beings that will shame us if we make a mistake.

But this is not true at all, computers are just boxes of metal that literally know nothing other than what we tell them. But that is also what makes them useful. Using computers does make our lives easier, for the most part, but this isn’t an accident. Humans build computers for humans, and nothing about the way they work is a coincidence.

In this blog post, I’d like to take you on a little journey to prove this to you, and to do that, we are going to take a very close look at how colours work on a computer.

Here's what's in store:

But more than that I hope I can give you a new appreciation for how these metal boxes actually work, and why they work the way they do.

🎨 Paint

If you think back to kindergarten or primary school, you might remember learning about mixing paints and something called a colour wheel.

Colour wheel. Image Credit.

The idea of a colour wheel is to show how colours related to each to other. To see this in action, I acquired some paint, and for this section I would love it if you could put yourself in the shoes of a little kid learning about paint and colour for the first time.

I have red, yellow and blue paint, but there are a lot of other colours that I might want to use in my painting. Fortunately, I can use my colour wheel to work out which colours to mix to get the other colours that I want.

So I mix yellow and red, I get orange:

Orange paint.

If I were to mix blue with yellow, I would get green.

If I were to mix red and blue, I would get violet.

The three colours I am using, Red, Yellow and Blue, are what we’d call primary colours, and they are actually the primary colours from the RYB colour model.

A colour model being any system that uses three primary colours to create more colours.

The colours that I just made using my primaries are called secondary colours.

If I mix a primary and a secondary, I can make a tertiary colour.

If I mix blue, which is my primary, and green, which is my secondary, I get “blue-green”:

Blue-green paint.

I’ve just made a few new colours here, three secondaries and a tertiary, but there are many more that I could make if I kept mixing.

We’d call the set of all the possible colours that I can produce using these three paints a gamut. And if I changed one of these paints to be a different brand that was maybe a slightly different shade, then I could produce a different gamut of colours.

We’re going to have to get a little physics-y here, because to understand how we can see colours, we need to understand a little bit more about light.

💡Light

When we think of light, what we are actually referring to is visible electromagnetic radiation, the key word being visible.

The electromagnetic spectrum is the range of frequencies covered by electromagnetic radiation, and is broken down into different bands of frequencies:

Diagram of the Electromagnetic Spectrum.

Image Credit.

This radiation travels in waves, so when we say “frequency”, we’re referring to how fast a wave is moving.

Gif showing wave moving.

Image Credit.

If you’re interested, the more detailed explanation is that we are measuring how many wavelengths pass a fixed point in a given amount of time, a wavelength being the distance between two crests in a wave.

Diagram showing the distance between two crests in a wave.

Anyway, back to the spectrum. Visible light is only a tiny band on this spectrum, but there are still many variations of wavelengths in that range.

Diagram showing the relative wavelengths of different colours of visible light.

Image Credit.

These different wavelengths are what influence our perception of colour. When we experience seeing red, we are seeing a long wavelength, and when we experience seeing violet, we are seeing a short wavelength, relatively speaking.

So the frequency of a wave determines what colour we see, but what is the connection between these waves and the paint that I was playing with earlier?

Well, imagine a white canvas.

At the moment, this white canvas by itself is reflecting all the visible light that hits it equally. It is not absorbing any light, it is all being reflected. We see this as white because this is the result of combining all of the colours from the visible spectrum.

Diagram showing every colour of light reflecting off a white surface.

But when I add some paint to the canvas, I see the colour of my paint instead.

Canvas with blue-green and black paint on it.

So when I added teal paint to the canvas, that paint is actually just reflecting blue and green light, and absorbing all other colours.

Diagram showing blue and green light reflecting off a blue-green surface.

When I mix all of blue, yellow and red, I get black.

When I add the black paint to the canvas, we see black. What is special about this is that the black paint is absorbing EVERY colour. In other words, no colour is being reflected, every light wave has been absorbed.

Diagram showing every colour of light being absorbed by a black surface.

This process of starting with a white canvas and adding paint to it is called subtractive colour mixing. I’ve started with a surface that reflects every wavelength, therefore we see white, and I’m subtracting colour from it.

Ok cool, so we can see how light bounces around and reflects off things, but how do we actually see it? What is it about our eyes that lets us see light?

👀 Eyes

Let’s look at how the human eye works.

Below is a diagram of the eye:

Annotated diagram of the human eye.

We have an iris, this is the coloured part of the eye, and it controls the size of the pupil. The pupil is what lets light into the eye.

In front of the iris is the cornea. The cornea is a protective layer to help prevent dirt and germs from getting into the eye.

On the other side of the iris is the lens.

The cornea and the lens work together to help us focus on objects at varying distances. They are what allow us to get a clear image of say your hand right in front of you, as well as someone on the other side of the room.

Curiously, some people can actually see UV light if their lens is damaged, which could be due to surgery or genetics.

Anyway, the light enters the eye, and is directed to the retina. The retina is the lining that covers most of the back of the eye. The retina receives light from the lens, converts it into electrical neural impulses, which get sent to the brain, via the optic nerve, where finally they are converted into visual perception. That is, we see light.

Let’s focus a little bit more on this retina thing. A retina contains millions of photoreceptor cells. These cells are what convert the light into electrical impulses.

There are two kinds of photoreceptor cells. These are rods and cones. We’ll start with cones.

We have 6-7 million cone cells, and these are what are responsible for perceiving colour. Typically, we have three kinds of cones, s, m and l, or short, medium and long cones. These names are based on whether they are sensitive to short, medium or long wavelengths.

Remember earlier when we were looking at the wavelengths of different colours? Our cones are most sensitive to wavelengths close to blue, green and red. So we tend to generalise the cones to simply blue, green and red cones.

So going back to our paint again… we said the blue-green paint is reflecting blue and green. So the blue and green, or S and M-Cones are being stimulated

As an aside, we are not all created equal. Not all of us see colours the same. For example, some people have colour vision deficiencies. So some of us have trouble detecting differences between colours, or cannot detect colour at all. This can happen when there are defects in the cone cells.

Even if you do not have a colour vision deficiency, you still experience colour in your own unique way. We do not all have the exact same number of cones, and therefore we do not see colour exactly the same as each other. So your blue is different to my blue.

The S, M and L cones are also not evenly distributed, meaning we do not have an equal number of each. We tend to have a lot more M and L cones than S cones. So when we are in brighter light, we are more sensitive to yellowish-green light because this stimulates the two most common cones, M and L. So we can see orange paint quite clearly in a bright room.

Cone cells are sensitive to colour, but not so sensitive to light. This is why we have rod cells. We have roughly 120 million rod cells, and they are very sensitive to light. These are what let us see in the dark, but they have almost no sensitivity to colours, which is why we don’t see colours as well in low light.

Table summarising cone and rod cells sensitivity to light and colour.

When we are in lower light levels, we are more sensitive to the wavelengths closer to blue, which is why you might notice a slight blue tint at night.

Speaking of light, and how we see in the dark. Let’s look at a different method of mixing colours, using light.

🔦 Light (again)

Instead of paint I've now got three torches, the colours I have are red, green and blue.

If I shine the red and blue torches on the same spot on a wall I get magenta:

Magenta colour generated on wall from blue and red lights overlapping.

If I were to shine the red and green torches on the same spot on a wall I would get yellow.

If I were to shine the blue and green torches on the same spot on a wall I would get cyan.

If I were to shine all three torches on the same spot I would get white.

Just like when I was using paint, I am using three primary colours to make new colours. My primaries are red, green and blue. These are the primary colours from the, very creatively named, RGB colour model. These are also the colours that the cones in our eyes are the most sensitive to, as we learned earlier.

Previously, when we were playing with paint, I mixed red, yellow and blue and got black. Now, when I shine red, green and blue, I see white.

This is because mixing lights of different colours, or wavelengths, uses a process of additive colour mixing. So we are creating a new colour by adding different wavelengths of light together.

Our wall started black and had colour added when we shined lights on it, as compared to our canvas which started white and had colour subtracted when we added paint.

🤔 Are white and black colours?

So a fun side note. There is actually a pointless ongoing debate between experts as to whether or not white and black are technically “colours” or not.

When we are thinking about light, white is the combination of all colours. So we’d call it a colour.

Meanwhile, black is the absence of colour, so we would not call it a colour.

But if we are thinking about colour as paint, it’s the opposite story.

As we’ve learned, we can combine red, yellow and blue to get black. So we could argue that black is a colour.

Meanwhile, white is the absence of colour. We cannot mix different colours of paint to create white, so we would say that white is not a colour... most of the time. We bleach things to make them white, such as paper, so maybe white is a colour sometimes?

Table summarising black and white colour status for paint vs light.

🖥 Colours and Screens

Ok, so now that we understand a bit more about how different colours of light interact, what is the connection between them and us writing software?

Think of a computer screen as being a huge grid, and each cell in the grid is one tiny element of the picture we see on the screen. These cells are actually called picture elements, or pixels for short.

I’ve created some pixel art here. Recall earlier when I said that I was not an artist. Imagine each cell in this grid represents one pixel on a computer screen:

Grid with blue cells to create a smiley face.

Each pixel is made up of three tiny lights, one is red, one is green and one is blue.

So computer screens also use the RGB model, just like we were using earlier when we were using the torches. So if I “zoom in” on one of these pixels, I can see that only the blue light is turned on, which is why we see blue. So just like with our torches, screens also use the RGB colour model.

Three circles representing red, green and blue lights. The blue light is turned on.

But colour models are somewhat arbitrary, they don’t have meaning or translation to “real life” on their own. This is where the idea of a colour space comes in.

Imagine this circle represents all visible colours of light.RGB represents a specific gamut from this circle.

[CIRCLE WITH RGB GAMUT]

So RGB cannot actually produce every colour, just those in this triangular shape.

RGB is a colour model, and then there are colour spaces based off this model. So for example, a common colour model is sRGB. sRGB, or standard RGB, was created by HP and Microsoft back in 1996, for use on monitors.

[RBG MODEL WITH sRGB SPACE]

These days sRGB is still very widely used, unless you have a modern Apple device, in which case you’ll be seeing Display P3.

So RGB is what we would call a device dependent model. Manufacturers use different colour spaces, and there will be slight variations in the materials they use in their screens as well, so the gamut of colours that can be produced will vary from screen to screen.

It is no coincidence that RGB is the preferred colour model for computer screens. It is because of the way our cones perceive colour, since we have red, green and blue cones, it makes sense that computer monitors use a model that matches that.

🔢 The Math of Colours on the Web

For the web designers and developers reading this, I’m hoping that combination of colours is sounding familiar to you. But just in case it’s not, or web development is not your usual thing, let me jog your memory.

Here is the world’s most boring webpage:

Empty webpage with blue background.

I’ve defined it’s background using the rgb() function in my CSS. There are a bunch of different ways to define colour in CSS, which we’ll get to later, but for now we are going to start with rgb:

html {
    background-color: rgb(0, 0, 255);
}

What I’m actually doing when I use this rgb function is I am changing the intensity of each of the red, green and blue lights in the pixels being used to display the webpage. The intensity is being defined by providing numerical values in the range 0 to 255. 0 being none of that colour, 255 being the maximum amount of that colour.

So the webpage was blue because I was using 0, 0 and 255. That is no red, no green, and maximum blue.

To get red I would use 255, 0 and 0. That is maximum red, no green and no blue.

If I want a colour other than a primary (red, green or blue), then I could combine two or more of these primary colours. For example, I could generate purple using:

html {
    background-color: rgb(128, 0, 128);   
}

Empty webpage with purple background.

Earlier we learned that creating colours by mixing lights is an additive colour method.

So if we use 0, 0, 0, the resultant colour is black, or no colour.

If we use 255, 255, 255, the resultant colour is white, that is, all the colours!

So why the range 0 to 255? It may seem arbitrary, but it actually relates to the binary representation of these numbers...

🔟 Decimal

Before we get into binary, let's just do a quick recap of our usual system. Us humans typically use a base 10 number system, also known as decimal. This means that we use 10 digits to represent numbers, ranging from 0 to 9.

Decimal numbers 0 to 9.

Since we have 10 digits to work with in our decimal system, the largest number we can represent using a single digit is 9:

9 represented as decimal number.

After that we have to add a second digit to the left, which gives us the next 90 numbers, and the highest number we can represent is 99.

99 represented as decimal number.

Then we need to add a third digit to the left, giving us the next 900 numbers, and the highest number we can represent is 999. A fourth digit gives us the next 9000 numbers, and so on….

So there is a pattern forming here, each digit is worth 10 times that to the digit on it’s right.

Take the number 123 for example. The 1 is worth 10 times as much as the 2, and the 2 is worth 10 times as much as the 3.

123 represented as decimal number.

0️⃣ 1️⃣ Binary

Computers however, are super dumb. Our decimal system is too complicated for computing for a variety of reasons, so computers only use a base 2 number system, i.e. they only have the digits 0 or 1.

Since there are only two options, we would call these binary digits, otherwise known as bits. A bit being a digit that can have two values. And all the information on a computer is represented using these bits.

Since there are only 2 digits to work with, this means that representing numbers in binary is a bit different to how we would in decimal.

Rather than being worth 10 times as much, each digit to the left is worth only twice as much as the digit to the right.

Take the number 1001 as an example.

1001 represented as binary number.

The rightmost digit is worth 1. The next digit on the left is worth 2. The next digit is worth 4. The next digit is worth 8.

The number 1001 means something to a computer, but to us humans that’s not so meaningful, so let’s convert it to decimal.

We’ll start on the right. We have the digit 1, and it’s worth 1. The next digit is 0, so we ignore it. The next digit is 0, so we ignore it. The next digit is 1, and it’s worth 8. So 8 + 1 = 9. In other words, 1001 is 9 in binary.

Let's look at another example:

1111 represented as binary number.

Again, we’ll start on the right:

  1. We have the digit 1, and it’s worth 1.
  2. The next digit is 1 and is worth 2. So we add 1 + 2 = 3.
  3. The next digit is 1, and is worth 4. So we add 3 + 4 = 7.
  4. The next digit is 1, and it’s worth 8. So 7 + 8 = 15.

So 1111 in binary is 15 in decimal.

So in binary, we can get to 15 by having 4 bits “turned on”. What’s interesting about this number is if we wanted 16, then we’d have to add another bit.

0️⃣ 1️⃣ 🌈 Binary and RGB

Let’s think back to our RGB codes for a second. When defining how much red, green or blue to use, we provide a number in the range 0 to 255.

255 in binary is 11111111, so that is 8 bits, all turned on. If we wanted the number 256, we’d have to add another bit. But in computing, we like our bits arranged in eights, also known as a byte. That is, a byte is 8 of these bits.

And RGB code has 3 components, red, green and blue. Each of these has a range of 0 to 255, that is 8 bits each, so we’d call this 24 bit colour.

With each bit having two states, 0 or 1, and there being 24 bits in total, that makes 2 to the power of 24 combinations of bits we can use to represent different colours. That’s roughly 16.7 million different colours.

Humans can only perceive about 10 million different colours, making 24 bit colour more than detailed enough for us to use to define colours on a screen.

Ok, so 16.7 million colours is a lot. These days our screens typically use 24-bit colour, otherwise known as True Colour, hence using 24-bit colour in our CSS. But this was not always the case. We didn’t always have 16.7 million colours at our disposal.

Instead, we had a list of named colours, which we still have in css today, and they really haven’t changed much at all, to their own detriment.

📜 A quick history lesson!

In 1995, 16 “basic colours” were defined in the HTML 3.0 specification. They were labelled as being in the sRGB colour space, and were considered the standard 16 colours to be supported by the Windows VGA Palette. In this context, VGA refers to a collection of standards created by IBM, and adopted by many others, for a way of driving displays.

So there were 16 standard colours, and then 124 extended colours. This idea being that there were 16 colours that should always be supported, and then 124 which were probably ok - and it was mostly ok, until you were using Opera 3.5 on Windows 98, in which case 14 colours were randomly missing 🤷‍♀️. Fortunately, by 2005, all modern browsers supported the full list.

Also interestingly, the CSS 2.1 spec promoted orange from the extended colour list to the basic colour list, making 17 basic colours in total. But CSS 3.0 then demoted it back down to the extended colour list.

Now, the working draft for the CSS level 4 colour module combines both lists, to make one list called the “Named Colours”.

But where did these names come from?

The list of colour names that we use originally came from the X Window System, which was software for managing open windows.

Screenshot of X11 software.

https://upload.wikimedia.org/wikipedia/commons/d/d4/X-Window-System.png

The X Window System was originally released in 1984, and included a file called rgb.txt. This file contained a list of colour names, which were mapped to RGB colour values.In 1987, X11 was released, and rgb.txt contained 69 colours.

This list eventually became a commonly used list of colours, known as the X11 Color Names. These names are still in CSS today.

Which led to me to discover this extract from the CSS specification:

Screenshot from CSS specification.

https://www.w3.org/TR/css-color-4/#named-color

Which itself says that the list is not good and is wildly inconsistent within itself. With names such as darkgray actually being lighter than gray.

Basically, these names were not thought through. They were never intended to become as widely used as they were. Software was built that used this list, designers got used to them, and basically it became impossible to introduce a new list.

But we did make some headway. In the 1990s, most displays were only capable of displaying 256 colours. Operating systems would also often reserve between 16 and 20 colours for their own use. So this meant that if there was a colour that the computer didn’t recognise, perhaps in an image, the operating system would use a method called dithering to fix it, which basically means adding some noise to the image to cover up the missing colour.

tl;dr; there was no consistency between monitors, operating systems and browsers. Colours were a mess.

Enter web safe colours. This was a standardised list of 216 colours that we could use on the web 🎉 But very shortly after they was introduced, computer screens got better. We got True Colour, or 24 bit colour as we mentioned earlier, and web safe colours weren’t needed anymore 🤦‍♀️.

So back to our colours. We’ve already looked at colour names, and rgb(). To css, these are the same thing. The colour names simply map to RGB values.

Another very common method for defining colour in css, is by using hex codes.

Hex codes

For context for anyone reading this who hasn’t used hex codes before, a hex code is a string of usually 6 characters and numbers that together represent a colour.

So for example, here are some hex codes representing different colours:

Four different coloured squares and their corresponding hex codes.

Let’s take a closer look at that purple box.

A hex code is broken into three colour components, red, green and blue.

And they are broken into groups of two. The first and second characters represent the red component, the third and fourth represent the green component, and the fifth and sixth represent the blue component:

Hex code for purple.

Hopefully this pattern looks familiar. Just like RGB, hex codes are also broken into three components. And, just like we learned earlier, RGB colour codes are converted to binary for the computer to use them. The same thing happens with hexadecimal, in fact, hexadecimal is actually just a shorthand for binary. So hexadecimal can be used elsewhere in computing, it is not just for colours.

Hexadecimal uses a base 16 numbering system. But in our base 10 numbering system we only have 10 digits to work with so we use the letters a - f to make up the last 6 characters.

Table showing hexidecimal numbering system.

So if we look at the first component of our purple colour here, the red component. In hexadecimal we have 5f.

Purple hex code with first component/two characters emphasised.

The first element, 5, which in binary is 0101. We add a leading 0 so that each element uses 4 bits exactly. The second element is f. F represents 15 in hex, and in binary this is 1111. Fast fowarding through the rest of the elements, the resulting binary for 5f3a8e is 0101 1111 0011 1010 1000 1110 in binary.

And this is why we use hex codes. Can you imagine writing binary like this in our css? That would be a mess and littered with errors.

Like I said earlier, hex codes are converted to binary. Each element in the hex code takes 4 bits to store, 4 x 6 is 24, so this again, represents a 24 bit colour.

The point I’m trying to make here, is that these things are all in the same. When we type a colour name, or use the rgb function, or write a hex code, in our css file, all we’re doing is making a choice about which synonym to use for a particular colour. The computer doesn’t care which one you use, because it’s going to be converted to binary anyway.

🌈 Other Colour Models

We’ve had a look at the RYB and RGB colour models, but there are actually a lot more where they came from.

HSL

For example, in CSS we could also use HSL, which is Hue, Saturation, Lightness:

Diagram showing HSL colour model.

Image Credit.

Hue is a degree on the colour wheel from 0 to 360. 0 would be red, 120 would be green, and 240 would be blue.

Saturation is a percentage value where 0% means a shade of grey and 100% is the full colour.

Lightness is also a percentage; 0% is black, 100% is white.

This model was added to the spec in CSS 3.0, so it’s been around for about 10 years or so.

CMY(K)

Another colour model that you may have come across, especially if you have ever worked in print, is CMY.

CMY has the primary colours cyan, magenta and yellow:

Diagram showing CMY colour model.

Image Credit.

CMYK is considered the industry standard for printed materials. The k stands for the key colour, and is nearly always black.

The reason we have to add black is because when using cyan, magenta and yellow, the darkest we could get is a dirty brown kind of colour, so we add black separately so we can get true shades of black and grey.

But earlier we were playing with paint to get black, so why not just use red, blue and yellow? Because CMY does a better job at covering the range of lighter colours.

A bunch more...

There are actually tonnes of different colour models and even more colour spaces, and we went through several of them today. I quickly chucked together a list of a few others if you were interested in learning about other colour models too:

Conclusion

So why? Why did I write this very long post about colour?

Well this started when I saw a front end developer and designer tweet about being mind blown when they discovered how hex codes work. And I thought, wait… people don’t know this stuff? I immediately realised that of course people don’t know this stuff, most people have hobbies, and don’t spend their weekends reading about light waves and retinas.

So I thought, that front end developer found that little snippet about hex codes interesting, I wonder if other developers would feel the same...

So that’s one reason. But more than that I think that given we spend so much time on computers, even those who don’t work in tech, we should have some kind of understanding about how they work. Like I said earlier, so many people feel overwhelmed by these boxes, but these boxes are useful tools and built specifically with us in mind. I hope the demonstrations we did here today helped to put that into perspective a bit more.

Computers don’t have to be a mystery and they certainly are not a source of intelligence. We are the intelligent ones for creating them and programming them. And I hope that the next time you are writing a colour code, you have a brief moment where you get to stop and pause and smile because you know how that code works 🙂