November 2026 · 4 min read
Colour theory for interfaces
Most colour theory was written for painters. It’s about harmony: which colours sit well together, and why. That still matters on a screen, but an interface asks more of colour. It has to mean something, keep meaning it in light and dark, and still work for people who don’t see it the way I do.
No colour stands alone
A colour never reaches you on its own. It arrives with everything around it, and your eye judges it against that. Put the same grey on a dark ground and on a light one, and you’d swear they were two different greys.
This is simultaneous contrast. It isn’t a fault in your eyes or your screen. Your visual system cares far more about differences than about absolute values, and here it’s doing exactly what it’s built to do.
In an interface, it means a colour can only be judged where it lives. A grey that reads as quiet on a white card can look heavy on a black one. A brand colour picked on a light mockup can turn harsh in dark mode. The swatch in the design file is where the decision starts, not where it ends.
It’s also why dark mode is more than the light theme turned inside out. Flip the values and every relationship shifts at once: borders that separated now glare, shadows that lifted now vanish, and the accent that was calm on white starts to buzz. Each theme needs its colours chosen against its own ground.
HSL against OKLCH
Most of us learned to pick colours in HSL: a hue, a saturation and a lightness. It feels fair. Give every hue a lightness of 50%, and they ought to look equally light.
They don’t. Yellow at 50% looks far lighter than blue at 50%, because HSL’s lightness is arithmetic on red, green and blue. It knows nothing about the eye, which sees green light as much brighter than blue light of the same strength.
OKLCH is built the other way round. Its lightness is designed to follow what you see, so equal numbers look close to equally light, whatever the hue. The figures beside each row are CIELAB lightness, a standard measure of how light a colour looks, worked out from the swatches as they’re drawn.
You can see the problem in any palette made by turning the hue wheel: a row of tags where the yellow one disappears into a white card and the blue one shouts. Each was given the same numbers, and none of them looks it.
That changes how a palette gets made. Set the lightness of each step once, choose the hues freely, and the contrast stays where you put it. It matters most for states. If success and error share a lightness, they carry the same weight on the page, and the hue and the icon do the talking. Every current browser supports it in CSS.
/* One lightness, two hues: neither shouts louder than the other. */
:root {
--success: oklch(0.53 0.16 142);
--error: oklch(0.53 0.18 29);
}One accent
The eye goes to whatever is different. It’s the most useful thing colour can do in an interface, and the easiest to waste.
If the button, the links, the tags, the icons and the chart all compete in colour, nothing leads. If everything is quiet apart from one thing, that thing answers ‘what do I do here?’ before anyone has read a word.
This site works that way. The type and the surfaces are one ink at different strengths, and foil is the accent, kept for the main action, the thing that’s selected, or the moment something’s done. Because it’s rare, it means something when it appears.
A quick test is to turn a design grey. If the hierarchy still holds, colour is adding meaning on top. If it falls apart, colour was doing work that size, weight and space should have done.
Contrast is a number
Taste chooses the colours. Maths checks that people can read them. WCAG’s contrast ratios are the floor: 4.5:1 for body text, and 3:1 for large text and for the parts of a control you need to see to use it.
Treat them as a floor, not a target. A grey that passes on white can fail on the off-white card beside it. Each theme needs checking on its own, too, because the same opacity says less on a light ground than on a dark one. Check colours where they’re used, at the size they’re used.
And colour should never be the only signal. A red error and a green success need more than their hue between them, which is a post of its own: the one on green and red.
Theory won’t pick the colours for you. What it does is tell you when your eye is being fooled, and that’s most of what I want from it.