ToolsAre.Us — Next-Gen Tools Hub ToolsAre.Us — Next-Gen Tools Hub

How colour works on a screen

Why averaging two colours gives mud, and why 50% lightness is not half as bright.

Last updated 2 September 2026 · ToolsAre.Us Guides

Colour on a screen looks like it should be simple arithmetic on three numbers. It mostly is — but two facts get in the way, and between them they explain nearly every surprising result: the numbers are not proportional to light, and light is not proportional to perception.

Additive colour, and what hex actually is

A screen emits light. Each pixel has three subpixels — red, green, blue — and colour is made by adding them. All three at full gives white; all three off gives black. This is the opposite of paint, where mixing pigments subtracts light and combining everything approaches black. It is why mixing red and green light produces yellow, which feels wrong to anyone whose intuition comes from a paintbox.

Each channel is normally 8 bits, so 0–255, giving 256³ ≈ 16.7 million combinations.

A hex colour is nothing more than those three numbers written in base 16. #FF8000 is red 255, green 128, blue 0. Each pair of characters is one channel, and the three-character shorthand #F80 simply repeats each digit, so it can only express 4,096 of the possible colours.

The first surprise: the numbers are not linear light

An RGB value of 128 does not emit half the light of 255. It emits roughly 21%.

The reason is that sRGB — the standard colour space for essentially all ordinary screen content — stores values with a gamma encoding, an exponential curve of roughly 2.2 rather than a straight line. This is not an accident of old hardware; it is a good use of limited bits. Human vision is far more sensitive to differences among dark tones than among bright ones, so allocating more of the 256 steps to the dark end puts precision where the eye can use it. A linear encoding at 8 bits would show visible banding in shadows.

The consequence bites whenever you do arithmetic on colours. Averaging two sRGB values does not give the colour halfway between them in light. Blending pure red #FF0000 and pure green #00FF00 by naive averaging gives #808000 — a dark, muddy olive, when the true midpoint in light terms is a much brighter yellow-green. This is why gradients between saturated colours often develop a dull band through the middle.

The correct procedure is to convert each channel to linear light, average there, and convert back. Graphics software does this; a quick hand-rolled blend usually does not.

The second surprise: HSL lightness is not brightness

HSL — hue, saturation, lightness — is a far more intuitive way to describe a colour than three channel values, and it is genuinely useful for building palettes. But its lightness component is a geometric construction, not a perceptual one.

Yellow at hsl(60, 100%, 50%) and blue at hsl(240, 100%, 50%) have identical stated lightness. They do not look remotely equally bright — the yellow is dazzling and the blue is dark. Human vision is far more sensitive to green wavelengths than to blue, and HSL takes no account of that.

This is why a palette built by holding lightness constant and rotating hue produces swatches of wildly varying apparent brightness, and why such a palette fails accessibility checks unpredictably.

Perceptual colour spaces exist to fix this. CIELAB, and the more recent OKLCH now supported in CSS, are built so that equal numerical steps correspond to roughly equal perceived steps. In OKLCH, two colours with the same lightness genuinely look equally bright regardless of hue, which makes generating a coherent palette far more predictable.

Contrast, and how the ratio is actually computed

Text legibility depends on contrast, and the accessibility standard defines it precisely. The calculation has three stages:

  1. Undo the gamma encoding on each channel, converting the stored value to linear light.
  2. Compute relative luminance as a weighted sum: roughly 0.2126 R + 0.7152 G + 0.0722 B. Those weights are the important part — green contributes over seven times as much perceived brightness as blue.
  3. Form the ratio (L_lighter + 0.05) / (L_darker + 0.05). The added constant models ambient screen glare and keeps the ratio finite.

The result runs from 1:1 (identical) to 21:1 (black on white). The WCAG thresholds:

ContentAA (minimum)AAA (enhanced)
Normal text4.5:17:1
Large text (18pt+, or 14pt+ bold)3:14.5:1
UI components and graphics3:1

Because green dominates the luminance calculation, two colours can look very different in hue and still fail badly — red text on a green background of similar luminance is nearly illegible despite being maximally different in colour. Contrast is about light, not about hue.

It is worth knowing that this formula is a simplification with acknowledged weaknesses, particularly for light text on dark backgrounds, where it tends to be more permissive than perception warrants. A successor algorithm (APCA) is under development for exactly this reason. Meeting the current thresholds is the standard, but checking dark-mode text by eye as well remains sensible.

Colour blindness

Around 8% of men and 0.5% of women of northern European descent have some form of colour vision deficiency, most commonly difficulty distinguishing red from green.

The practical rule is simple and rarely followed: never encode meaning in colour alone. A red-versus-green status indicator carries no information for a substantial fraction of readers. Add a shape, an icon, a label or a pattern so the colour is reinforcing rather than carrying the message. Charts should distinguish series by more than hue — line style, direct labelling, or markers.

Adequate contrast helps here too, since a difference in lightness survives when a difference in hue does not.

Why the same colour looks different on two screens

Practical guidance

← All guides