Contrast Grid
Audit a whole palette at once — every text and background pairing with its WCAG ratio in a single grid, so you can see which combinations are usable.
Rows are text colors, columns are backgrounds. Each cell renders the actual pair with its ratio; ✓ marks pairs at or above the chosen bar. Audit a whole design-system palette at once.
A 12-colour grid draws 132 cells and contains 12 numbers
The WCAG formula puts the lighter colour on top by definition, so it cannot tell which of the two you meant as text: the ratio of A on B and B on A is the same number. Checked on 20,000 random pairs with no exceptions. The grid is therefore symmetric about its diagonal, and the summary line above counts cells rather than pairs — so it reports twice as many passes as there are decisions to make.
| Colours | Cells drawn | Distinct pairs |
|---|---|---|
| 2 | 2 | 1 |
| 6 | 30 | 15 |
| 8 | 56 | 28 |
| 12 | 132 | 66 |
It compresses further than that. The ratio is (lighter + 0.05) / (darker + 0.05) and nothing else — hue and saturation never appear. Two completely different-looking colours with the same relative luminance produce identical rows, so an n by n grid has n degrees of freedom rather than n squared. Recomputing 5,000 random pairs from luminance alone reproduces the ratio exactly every time.
Sort by luminance and every row is a bowtie, not a staircase
Fix a text colour at luminance L and a bar of r. A background passes if its luminance is at least r(L + 0.05) − 0.05, or at most (L + 0.05)/r − 0.05. Two half-lines with one gap between them — which those formulae predict for all 6,000 test marks with zero mismatches. So the passes are not one block. A row can pass at both ends of the luminance ordering at once, which is what I assumed it could not and is false on this page's own default palette at 3:1. It is the failures that form one unbroken band in the middle — verified on 15,000 random palette-and-bar combinations without exception.
| Palette colour | Relative luminance |
|---|---|
| #1a1a2e | 0.0116 |
| #6c5ce7 | 0.1661 |
| #fd79a8 | 0.3738 |
| #00b4d8 | 0.3760 |
| #f5f6fa | 0.9223 |
| #ffffff | 1.0000 |
Scored against each bar, that palette gives 7 of 15 pairs at 3:1, 5 of 15 pairs at 4.5:1 and 2 of 15 pairs at 7:1.
The three pass bars are in three different regimes, because 3 × 7 = 21
Push the thresholds to their limits. A colour can pass against something lighter only if the luminance that would take is still on the scale, so only if L ≤ 1.05/r − 0.05. It can pass against something darker only if L ≥ 0.05r − 0.05. Those two limits move in opposite directions as the bar rises, and the three options in the dropdown land in three genuinely different places.
| Bar | Lighter partner needs L ≤ | Darker partner needs L ≥ | Between them |
|---|---|---|---|
| 3:1 | 0.300 | 0.100 | works against both, 20.00% wide |
| 4.5:1 | 0.183 | 0.175 | works against both, 0.83% wide |
| 7:1 | 0.100 | 0.300 | works against neither, 20% wide |
At 3:1 there is a comfortable band of colours that work against both white and black. At 4.5:1 that band is 0.83% of the luminance range. At 7:1 it has not merely closed — it has inverted into a band where a colour works against neither extreme, and it is exactly the same interval, 0.1 to 0.3, that was comfortable at 3:1.
That mirroring is not a coincidence. 21 is the largest ratio the formula can produce — white against black — and the two limits coincide for any pair of bars whose product is 21, checked on six such pairs the page does not even offer. Three and seven are the two ends of this dropdown. The crossover, where the band closes to nothing, is √21 ≈ 4.583. And the AA bar of 4.5 sits just below it: 4.5 squared is 20.25, short of 21 by 0.75. That margin is the entire reason a colour passing against both white and black exists at all.
How to use
- Enter or paste your palette colours.
- Read the grid of every pairing.
- Note which combinations pass AA and AAA.
- Fix or retire the pairings that fail.
Frequently asked questions
Why audit the whole palette rather than one pair?
Because a design system gets used in combinations nobody planned. Checking pairs as they come up catches problems late and inconsistently; a grid shows immediately which of your colours can carry text on which, so the constraints are known before anyone builds against them.
What do the levels mean?
AA is the standard most organisations are held to, requiring 4.5 to 1 for body text and 3 to 1 for large text. AAA is stricter at 7 to 1, and is generally a goal rather than a requirement — some brand palettes cannot reach it at all without abandoning their colours.
Should every pairing pass?
No, and expecting it to leads to a grey, undifferentiated palette. What matters is knowing which pairings are safe for text, which are safe only for large text, and which are decorative. A grid that is mostly failures is fine if the passing cells cover the uses you actually need.
How many colours should a palette have?
Fewer than most palettes end up with. A base, a small number of accents, and a systematic lightness ramp for each covers the great majority of interface needs. Sprawling palettes produce exactly the situation this grid exposes: many colours, few legal combinations, and inconsistent use.
Does this cover colour blindness?
Only indirectly. Good luminance contrast helps considerably, since it is what remains distinguishable when hue perception is reduced. But two colours can have adequate contrast and still be confusable in a specific deficiency, so avoiding colour as the sole carrier of meaning remains a separate requirement.
What about text over images or gradients?
The grid cannot help there, because the background is not one colour. Those cases need checking at the worst point of the background, usually with an overlay or a solid panel behind the text to make the contrast predictable.
🔒 This tool runs entirely in your browser. Nothing you enter is uploaded, logged, or stored.