Contrastproof
Writing

One brand color is not enough, and tinting it does not help

5 min read

Key takeaways

  • One brand color cannot serve as a button surface, body-sized link text and a tinted background, because those uses need different lightness, not different hue.
  • Contrast ratio is symmetric, so a mid-tone color that fails as text on white fails by exactly the same number when it carries white text. Swapping which one is the text changes nothing.
  • Mixing toward white and black in sRGB produces steps that are perceptually uneven, bunched in the middle and muddy at the ends.
  • Building a scale in OKLCh at even lightness steps gives evenly spaced shades, and lets hue be held exactly across the whole range.
  • Chroma has to fall off toward both ends of the scale, because the sRGB gamut narrows there and a flat chroma target gets silently clamped.
  • A mid-tone color usually needs a darker step of itself to be text, while the original stays useful as a surface for dark type.

Where one color runs out

A brand arrives with one hex. It then has to be a filled button, the text of a link on white, a hover state darker than the button, a focus ring, a tinted background for a notice, and a border on that notice.

Those uses pull in opposite directions. Text on white wants the color dark. A tinted background wants it light. A surface carrying white type wants it dark again. Nothing satisfies all of them, which is why a one-color system ends up using the same value everywhere and failing at several of the jobs.

Take a mid-tone violet of the kind thousands of products ship. As body-sized link text on white, it falls just short.

The brand color as link text on white
#8b5cf6 on #ffffff16px · 400 · needs 4.5:14.23:1fix #8757f1 (4.50:1)

Here is the part that catches people out. Putting white text on that color does not rescue anything, because it is the same measurement. Contrast ratio is symmetric: the ratio between two colors does not care which one is the text.

White text on the brand color, as a filled button
#ffffff on #8b5cf616px · 400 · needs 4.5:14.23:1fix #100f10 (4.52:1)

One color, two uses, both failing, and by exactly the same number. A mid-tone color sits too far from white to be text on it and too far from white to carry it, at once. That is not bad luck, it is what the middle of the lightness range means.

It is not useless. Black text on it reaches 4.96:1, so it works as a surface for dark type. What it cannot do is be the only shade you have.

Why mixing toward white does not give you a scale

The usual next move is to generate the missing shades by mixing toward white and black, either by hand or with a lighten() style function. This is where scales go wrong, and the reason is sRGB.

sRGB values are not perceptually spaced. Equal numeric steps are not equal visual steps, so a scale built by even mixing has shades that crowd together in the middle, where you cannot tell 500 from 600, and shades that go flat and grey at the ends. Most hand-mixed scales have two or three steps nobody ever uses because they are indistinguishable from their neighbours.

Hue drifts too. Mixing a saturated blue toward white in sRGB pulls it toward purple on the way. The 100 and the 700 of a scale built this way are recognizably different colors, which defeats the point of a scale.

Even steps mean even lightness, which means OKLCh

OKLCh separates a color into lightness, chroma and hue, and its lightness axis is built to be perceptually uniform. Even steps in that axis look even.

That gives two things at once. Steps that are actually distinguishable from each other, and hue held exactly across the whole range, because hue is its own coordinate and simply does not move unless you move it. The 50 and the 950 are the same color at different lightnesses rather than two related colors.

Chroma should fall off toward both ends deliberately, on a curve. Every well-known scale has that shape, and it is not a stylistic choice; it is the shape of the space the colors have to fit inside.

Which step to use for what

Once the scale exists, the question becomes which step goes where, and that is a contrast question rather than a taste one.

UseNeedsAgainst
Link or body text on white4.5:1the page
Large heading on white3:1the page
White text on a filled button4.5:1the button surface
Button border, focus ring3:1what is behind it
Tinted notice backgroundno requirement itselfbut its text needs 4.5:1 on it

Reading it off a scale where every step already carries its measured contrast against white and black turns that from a guessing exercise into a lookup.

Accessible rampOne color in, a full 50 to 950 scale out, every step measured and labelled with what it is safe for.

If you only need to settle one pairing rather than build the whole range, the pair checker answers it directly and gives you the nearest passing shade.

Contrast checkerFor when the question is one specific combination rather than a whole scale.

The brand survives this

The objection to any of this is that it will not look like the brand any more. It is worth being concrete about how much actually changes.

Hue is held exactly, so the color is the same color. Only lightness moves, and often by very little: many failing pairs are repaired by a change well under the threshold at which anyone notices a difference side by side. The brand color also stays exactly itself wherever it already works, which for most brands is the button it was chosen for.

What changes is that the link text, which was already failing, becomes a darker step of the same color instead of the one shade that happened to be in the brand guidelines.

Common questions

Why does my brand color fail as link text on white?
Because a mid-tone color is too close to white in lightness. The same measurement also means white text sitting on that color fails, since contrast ratio is symmetric and does not care which of the two colors is the text. A mid-tone brand color usually needs a darker step of itself for text, and can keep the original as a surface for dark type.
Why should a color scale be built in OKLCh rather than by tinting?
sRGB is not perceptually uniform, so evenly mixing toward white and black produces steps that crowd in the middle and go flat at the ends, and hue drifts along the way. OKLCh has a perceptually uniform lightness axis and keeps hue as its own coordinate, so even steps look even and the hue holds exactly.
Should chroma stay constant across a color scale?
No. The sRGB gamut narrows at both the light and dark ends, so a constant chroma target cannot be rendered there and is silently clamped. Chroma should follow a curve that peaks near the middle of the scale and falls off toward both ends.
How many steps does a brand color scale need?
Eleven steps from 50 to 950 is the common convention and covers the usual jobs: tinted backgrounds at the light end, borders and disabled states in the middle, and text and hover states at the dark end.

Find out which of these your own site does.

Free, no account, under 30 seconds.