Bhinish Dhiman

Complementary, triadic and analogous colours: how to make each harmony readable

Complementary colours sit 180° apart on the hue wheel, triadic colours 120° apart, analogous colours 30° either side of the base. All three describe hue only, and WCAG contrast is computed from luminance alone, so a harmony guarantees nothing about readability. In the harmony tool every rotated colour keeps the base's OKLCH lightness, so members are near 1:1 against each other: take text from a lightness change, not another hue.

Colour harmonies are long-standing rules of thumb, and they answer a narrower question than people ask of them. They say which hues belong together. They say nothing about whether one of those hues can be read on another, and the reason is in the arithmetic of contrast itself.

The three harmonies, defined

Complementary colours are two hues on opposite sides of the hue wheel, 180° apart.

Triadic colours are three hues spaced evenly around the wheel, 120° from each other.

Analogous colours are a base hue and its neighbours; the colour harmonies tool uses the hues 30° either side.

These rules are long-standing conventions, not findings from measurement. Their value is that they cut an infinite space of choices down to a handful you can defend. The tool offers six, and the note it shows under each is worth reading as a warning label.

Harmony Hue offsets from the base Colours What separates them The tool’s note
Analogous 0°, −30°, +30° 3 Hue Neighbouring hues. Calm, and the safest default for interfaces.
Complementary 0°, 180° 2 Hue Opposite hues. Maximum separation, which also makes it the easiest to overuse.
Triadic 0°, 120°, 240° 3 Hue Three evenly spaced hues. Lively, and hard to balance without one dominating.
Split complementary 0°, 150°, 210° 3 Hue The opposite hue, split in two. Most of the contrast, less of the tension.
Tetradic 0°, 90°, 180°, 270° 4 Hue Two complementary pairs. Rich, and usually one pair too many for a UI.
Monochromatic None; lightness 0.32, 0.52 and 0.72 3 Lightness One hue at different lightnesses. Survives every kind of colour blindness.

The “maximum separation” in the complementary note is separation in hue. As the next section shows, it is not separation in contrast.

Why a harmony cannot promise contrast

The WCAG contrast ratio is computed from relative luminance and nothing else. Luminance is a weighted sum of the linearised red, green and blue channels, 0.2126 R + 0.7152 G + 0.0722 B, and there is no term for hue in the ratio. Two colours of any hues at the same luminance score 1:1.

The harmony tool makes this concrete. Every rotated colour is built at the base’s own OKLCH lightness and chroma, with only the hue turned. Where a turned hue cannot hold that chroma on screen, the chroma is pulled in and the lightness left alone. So every member of a complementary, triadic, analogous, split complementary or tetradic set has the same OKLCH lightness as the base.

For neutral colours, the same OKLCH lightness means exactly the same luminance, so the ratio would be exactly 1:1. Real hues at one lightness differ in luminance a little, so expect ratios between members close to 1:1, nowhere near the 3:1 that even large text needs. A complementary pair can look loud and still be unreadable when one is set as text on the other.

Monochromatic is the exception because it varies lightness instead. Its three colours are built at OKLCH lightness 0.32, 0.52 and 0.72 at the base’s hue, whatever the base’s own lightness, so the colour you entered is not among them unless its lightness matches one. For a neutral version, where relative luminance is the cube of OKLCH lightness, the arithmetic runs:

  • darkest on lightest: (0.72³ + 0.05) ÷ (0.32³ + 0.05) ≈ 5.1:1
  • middle on lightest: (0.72³ + 0.05) ÷ (0.52³ + 0.05) ≈ 2.2:1
  • darkest on middle: (0.52³ + 0.05) ÷ (0.32³ + 0.05) ≈ 2.3:1

Only the darkest on the lightest is a body-text pair, and not by a wide margin. The tool shows each colour’s ratio against white and against black but not between members, so to compare two swatches with each other, divide the larger on-white figure by the smaller. The 1.05 in the formula cancels, which makes that exact before rounding.

Building a harmony and reading its audit

  1. Set the base colour. Use the swatch or type into the hex field beside it; it accepts hex, rgb(), hsl() or oklch(). The tool opens on #2563eb.
  2. Choose a harmony. Six buttons under “Harmony”, with the note for the current one below. The H key moves to the next harmony on the same base, and Random base (or the R key) keeps the harmony and picks a new base.
  3. Read each swatch. Under its hex code are two lines: “on white” and “on black”, each with a ratio and a verdict of AA, large only or fails. Because a colour’s two ratios always multiply to 21, every swatch passes AA on one of the two grounds. What matters is which one your text will sit on.
  4. Read the audit panel. Its heading reads “Every pair survives colour blindness” or names how many pairs collapse. Each collapsing pair is listed with the vision types it fails under. The test simulates eight types of colour-vision deficiency and flags a pair whose CIEDE2000 distance falls below 11.
  5. Copy the CSS. The panel at the bottom writes the set as --palette-1, --palette-2 and so on, and Copy puts it on the clipboard. Share copies a link to the same set, and Save here keeps it on this device.

Making each harmony readable

The common move for all of them: keep the harmony for fills, accents and chart series, and take text from a lightness change on one of its hues.

Complementary

Two colours at one lightness. Neither works as text on the other, so let one carry most of the area and use the other sparingly. For text, use a dark step of either hue; the ramp and token generator builds eleven steps of one hue and names the one that clears 4.5:1 on white.

Triadic and split complementary

Three hues at one lightness, all competing at the same visual weight. Pick one to dominate, as the tool’s note advises, and draw text from a neutral or a dark step rather than from the set. These are also the sets where hue does all the separating, so read the audit before you use them to distinguish anything, such as series in a chart.

Analogous

Neighbours 30° apart at the same lightness lean entirely on hue to stay distinguishable. That makes them calm as backgrounds and accents, and it means the colour-vision audit is the check to trust if any two of them have to mean different things. Separate those two by lightness, or add a second cue: the tool’s notes point to WCAG 1.4.1, which asks that colour is never the only carrier of meaning.

Monochromatic

Already separated by lightness, which is why the tool’s note says it survives every kind of colour blindness. It is the one harmony that contains its own text pair: the darkest member on the lightest, at roughly 5:1 in the neutral arithmetic above.

Other ways to do it

There is no built-in method on macOS, Windows or iPhone for building colour harmonies, and no command-line route among those these guides vouch for. On paper, a hue wheel gives you the angles; the contrast checker then tells you which of the results can carry text, and the nearest version of each that can.

Checking that nothing is sent

Nothing is uploaded, because there is nothing to upload: the base colour and harmony are stored after the # in the address bar, and browsers do not send that part of a URL to the server. Watch the Network panel in DevTools while you switch harmonies and you will see nothing carrying them.

Open colour harmonies, try your base as a triad and then as a monochromatic set, and compare what the audit says. For building a set that survives colour-vision deficiency from the start, see How to build a colour-blind safe palette.