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.
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.
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.
| Use | Needs | Against |
|---|---|---|
| Link or body text on white | 4.5:1 | the page |
| Large heading on white | 3:1 | the page |
| White text on a filled button | 4.5:1 | the button surface |
| Button border, focus ring | 3:1 | what is behind it |
| Tinted notice background | no requirement itself | but 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.