Colour Contrast and Accessible Palettes
Contrast is the accessibility requirement that is easiest to measure and easiest to get wrong, because the thing being measured is not what your eye reports. Two colours can look clearly different and still fail; two that look similar can pass. Understanding what the ratio is computed from makes the failures predictable instead of mysterious.
What the ratio actually measures
A contrast ratio compares the relative luminance of two colours — roughly, how much light each one emits — on a scale from 1:1 for identical colours to 21:1 for black on white. Luminance is not the average of the channels: green contributes far more than red, and red far more than blue, because human vision is most sensitive in the middle of the spectrum. That weighting is why bright yellow text on white fails badly while the same yellow on black passes easily.
The consequence is that hue barely matters and lightness dominates. Two vivid, obviously different hues at the same lightness have almost no contrast by this measure, which is exactly the case where designers are most surprised by a failing score. If a pairing fails, changing the lightness will fix it; changing the hue usually will not.
The thresholds, and which one applies
WCAG asks for 4.5:1 for normal body text and 3:1 for large text, where large means about 24px, or 19px when bold. That is level AA; level AAA raises them to 7:1 and 4.5:1. The large-text allowance exists because thicker strokes cover more pixels and remain legible at lower contrast — it is a concession to letterform weight, not a loophole.
Non-text elements have their own rule that is frequently missed: interface components and meaningful graphics need 3:1 against what is next to them. That covers the border of an input, the focus ring, the bar in a chart, an icon carrying meaning on its own. Placeholder text and disabled controls are the usual offenders, often sitting well below any threshold on the grounds that they look intentionally faint.
Passing the ratio is not the same as being readable
The ratio knows nothing about type. The same colours at 4.6:1 are comfortable in a 16px regular weight and hard work in a 12px light weight, because thin strokes cover fewer pixels and lose more to antialiasing. Meeting the threshold is a floor, not a target, and body text usually wants to clear it with room to spare.
Nor does the ratio know what is behind your text. Text over a photograph, a gradient or a video has a different contrast in every region, and the number computed against one sampled pixel says nothing about the rest. Those cases need a scrim, a solid panel or a text shadow — something that guarantees a known background rather than hoping for one.
Colour blindness changes which pairs work
Around one in twelve men has some form of colour vision deficiency, most commonly difficulty separating red from green. Contrast ratios already survive this reasonably well, since they are driven by lightness — but any information carried by hue alone does not. A red-versus-green status dot, a chart whose only key is colour, a link distinguished from body text by colour with no underline: each is invisible to a substantial slice of readers.
The rule that follows is simple: never let colour be the only channel. Add a shape, an icon, a label, a pattern or a difference in lightness alongside it. Checking a design through a simulation of the common deficiencies is quick, and it tends to catch exactly the charts and status indicators that automated contrast checkers pass without complaint.
Building a palette that holds up
The most reliable approach is to design in lightness steps rather than picking colours individually. Fix a ladder of lightness values, generate each hue at every step, and pairings become predictable: any step far enough from another on the ladder will pass, regardless of hue. Perceptual colour spaces make this far easier than HSL, whose lightness is not perceptually uniform — two HSL colours at the same lightness value can look nothing alike in brightness.
A working checklist:
- Body text 4.5:1, large text 3:1, interface borders and meaningful icons 3:1.
- Fix failures by changing lightness, not hue.
- Check placeholder, disabled and focus states — they fail most often.
- Never encode information in hue alone; add shape, label or lightness.
- Test both themes: a palette that passes in light mode can fail inverted.