A high contrast palette is a set of brand colours where text stays easy to read on its background. WCAG 2.2 measures this as a ratio from 1:1 to 21:1. Body text needs at least 4.5:1 for level AA and 7:1 for AAA; large text needs 3:1 and 4.5:1. The palettes here list every pair.
| Content | Level AA | Level AAA |
|---|---|---|
| Body text | 4.5:1 | 7:1 |
| Large text (18pt, or 14pt bold) | 3:1 | 4.5:1 |
| Icons, input borders, focus rings | 3:1 | No extra level |
| Logos and pure decoration | No requirement | No requirement |
Updated
Most palette sites show pretty swatches side by side, which says nothing about whether text placed on them can be read. Each palette below gives a colour a job (background, text, secondary text, accent, text on the accent) and checks the pairs you would really put together on a page.
Pick a palette, then change any colour. Every pair is rechecked as you type.
Starting palette: Ink on paper, Night shift, Forest ledger, Harbor blue, Warm clay
Opening hours
Open Tuesday to Saturday, 9 to 5. Walk-ins welcome before noon.
Closed on public holidays.
Book a visit
Everything is calculated in your browser.
Ratios are calculated with the WCAG 2.2 formula and shown cut down to two decimals.
| Palette | Pair | Ratio | Body text | AAA body text |
|---|---|---|---|---|
| Ink on paper | Body text #111827 on Background #FFFFFF | 17.73:1 | AA | AAA |
| Ink on paper | Secondary text #4B5563 on Background #FFFFFF | 7.55:1 | AA | AAA |
| Ink on paper | Accent and buttons #1D4ED8 on Background #FFFFFF | 6.70:1 | AA | No |
| Ink on paper | Text on the accent #FFFFFF on Accent and buttons #1D4ED8 | 6.70:1 | AA | No |
| Night shift | Body text #F8FAFC on Background #0B1220 | 17.89:1 | AA | AAA |
| Night shift | Secondary text #CBD5E1 on Background #0B1220 | 12.61:1 | AA | AAA |
| Night shift | Accent and buttons #FBBF24 on Background #0B1220 | 11.21:1 | AA | AAA |
| Night shift | Text on the accent #0B1220 on Accent and buttons #FBBF24 | 11.21:1 | AA | AAA |
| Forest ledger | Body text #1B3A2A on Background #F7F5EF | 11.42:1 | AA | AAA |
| Forest ledger | Secondary text #44403C on Background #F7F5EF | 9.42:1 | AA | AAA |
| Forest ledger | Accent and buttons #9A3412 on Background #F7F5EF | 6.70:1 | AA | No |
| Forest ledger | Text on the accent #FFFFFF on Accent and buttons #9A3412 | 7.30:1 | AA | AAA |
| Harbor blue | Body text #FFFFFF on Background #0F2E4C | 13.85:1 | AA | AAA |
| Harbor blue | Secondary text #D6E4F0 on Background #0F2E4C | 10.69:1 | AA | AAA |
| Harbor blue | Accent and buttons #7DD3FC on Background #0F2E4C | 8.31:1 | AA | AAA |
| Harbor blue | Text on the accent #0F2E4C on Accent and buttons #7DD3FC | 8.31:1 | AA | AAA |
| Warm clay | Body text #431407 on Background #FFF7ED | 14.74:1 | AA | AAA |
| Warm clay | Secondary text #57534E on Background #FFF7ED | 7.18:1 | AA | AAA |
| Warm clay | Accent and buttons #B91C1C on Background #FFF7ED | 6.09:1 | AA | No |
| Warm clay | Text on the accent #FFFFFF on Accent and buttons #B91C1C | 6.47:1 | AA | No |
Name variables by role, not by colour, so swapping a palette later is one edit per line.
<style>
:root {
--bg: #FFFFFF;
--text: #111827;
--muted: #4B5563;
--accent: #1D4ED8;
--on-accent: #FFFFFF;
}
body { background: var(--bg); color: var(--text); font: 16px/1.5 system-ui, sans-serif; padding: 16px; }
small { color: var(--muted); }
button { background: var(--accent); color: var(--on-accent); border: 0; border-radius: 999px; padding: 8px 16px; font: inherit; }
</style>
<p>Fresh bread from 7am, every day but Monday.</p>
<small>Prices include tax.</small>
<p><button>Order ahead</button></p>The same calculation the tester runs, written from the W3C definition of relative luminance.
function luminance(hex) {
const n = parseInt(hex.replace("#", ""), 16);
const lin = (c) => {
const s = c / 255;
return s <= 0.04045 ? s / 12.92 : ((s + 0.055) / 1.055) ** 2.4;
};
return 0.2126 * lin(n >> 16) + 0.7152 * lin((n >> 8) & 255) + 0.0722 * lin(n & 255);
}
function contrast(a, b) {
const [hi, lo] = [luminance(a), luminance(b)].sort((x, y) => y - x);
return (hi + 0.05) / (lo + 0.05);
}
contrast("#111827", "#FFFFFF"); // about 17.7
A palette of five colours has ten possible pairs, and most of them never meet on a real page. Naming a role for each colour tells you which pairs matter, so you test four combinations instead of guessing.
The role that most often fails is secondary text: the pale grey used for dates, captions and footnotes. It is also the text people squint at most.
Keep your brand colour as the accent and adjust its lightness until the button text passes. A shade darker or lighter usually keeps the brand feel while fixing the ratio.
If your brand colour is a light yellow or a pale blue, use it for backgrounds and large shapes, and pick a dark partner for anything people need to read.
There is no single official line called high contrast. WCAG level AA asks for 4.5:1 for normal text and level AAA asks for 7:1, so many designers treat 7:1 for body text as the high contrast target.
WCAG treats text of at least 18 point, or 14 point bold, as large. The W3C explainer puts those at roughly 24px and 18.5px in CSS pixels.
No. The W3C says the ratio is not rounded, so a pair at 4.499:1 does not meet 4.5:1. The tester cuts values down for this reason.
Yes. WCAG 2.2 success criterion 1.4.11 asks for at least 3:1 between parts of controls and meaningful graphics and the colours next to them.
No. Text that is part of a logo or brand name has no contrast requirement under 1.4.3. Everything else on the page around it still does.
Related: Color contrast checker, Accessible color palette generator, Bad color contrast examples and fixes, Best fonts for websites.
Start for free or see all free tools. We.Inc is free to start, with no card needed. AI building is on paid plans from $20 a month.
We.Inc is an AI-powered website builder you can resell under your own brand. Launch a branded client dashboard, bill on Stripe Connect, and deliver AI-generated websites in minutes. White-label plans start at $99 a month for 25 client sites, with a 7-day free trial and no per-site fees.