If you've ever run an accessibility audit and seen "contrast ratio fails WCAG AA" — this post explains what that actually means, how the math works, and when each threshold applies.
What is color contrast ratio?
Contrast ratio is a number between 1:1 and 21:1 that describes how different two colors appear to a human eye.
- 1:1 = identical colors (white on white, invisible)
- 21:1 = maximum contrast (black on white)
The ratio is calculated from the relative luminance of both colors — a measure of how bright a color appears to human perception, weighted for how our eyes respond to different wavelengths (we're more sensitive to green than blue, for example).
The WCAG standards
The Web Content Accessibility Guidelines (WCAG) define two levels:
AA (the baseline — required for most sites)
| Element | Minimum ratio |
|---|---|
| Normal text (< 18pt or < 14pt bold) | 4.5:1 |
| Large text (≥ 18pt or ≥ 14pt bold) | 3:1 |
| UI components and graphics | 3:1 |
AAA (enhanced — harder to achieve)
| Element | Minimum ratio |
|---|---|
| Normal text | 7:1 |
| Large text | 4.5:1 |
Which level do you need? WCAG AA is the standard referenced in most legal accessibility requirements (ADA in the US, EN 301 549 in the EU). AAA is aspirational — some WCAG documents note it can't always be achieved for all content.
How the math works
The formula for contrast ratio is:
(L1 + 0.05) / (L2 + 0.05)
Where L1 is the lighter color's relative luminance and L2 is the darker one's.
Relative luminance is derived from the RGB values after converting from sRGB (the gamma-corrected color space your screen uses) to linear light values:
// Simplified
function relativeLuminance(r, g, b) {
const [rLin, gLin, bLin] = [r, g, b].map(c => {
const s = c / 255;
return s <= 0.04045 ? s / 12.92 : Math.pow((s + 0.055) / 1.055, 2.4);
});
return 0.2126 * rLin + 0.7152 * gLin + 0.0722 * bLin;
}
The weighting (0.2126, 0.7152, 0.0722) reflects that human eyes are most sensitive to green and least sensitive to blue.
You don't need to do this by hand — but understanding why light gray on white fails while dark gray passes makes the rule make more sense.
Common mistakes and how to fix them
1. Light gray text on white backgrounds
/* Fails AA — ratio ~4.0:1 */
color: #767676;
background: #ffffff;
/* Passes AA — ratio 4.5:1 */
color: #737373;
background: #ffffff;
One shade darker. That's often all it takes.
2. Colored text on colored backgrounds
Brand colors frequently fail. A blue button with white text might look readable but still fail.
/* Many brand blues fail with white text */
background: #4A90E2; /* ratio ~2.9:1 with white — fail */
background: #1a73e8; /* ~4.6:1 with white — pass */
3. Placeholder text
Placeholder text in inputs is usually styled with low opacity or light gray. It's exempt from contrast requirements in WCAG 2.1 — but it's still bad UX to make it unreadable.
4. Disabled states
Disabled form elements are also exempt from contrast requirements under WCAG.
Which pairs pass?
Some quick reference points for text on white (#ffffff):
| Text color | Ratio | Result |
|---|---|---|
| #000000 (black) | 21:1 | ✅ AAA |
| #595959 | 7.0:1 | ✅ AAA |
| #767676 | 4.5:1 | ✅ AA |
| #949494 | 2.9:1 | ❌ |
| #cccccc | 1.6:1 | ❌ |
How to check contrast quickly
There are a few ways to check:
In browser DevTools: Chrome and Firefox both show contrast ratio in the color picker when you click a color in the Styles panel. Look for the WCAG badge.
In design tools: Figma's accessibility plugin and Sketch's Stark plugin show contrast as you pick colors.
Standalone checker: I built a free, client-side tool that checks any two colors instantly: SnappyTools Color Contrast Checker
It shows the ratio, WCAG AA/AAA pass/fail for normal text, large text, and UI components — and lets you swap foreground and background to test both directions.
The practical approach
Don't start from scratch trying to hit 4.5:1. Instead:
- Pick your background color
- Use a checker to find the darkest text shade that fits your palette
- For link colors (often the hardest): check both against the background AND against surrounding body text (links inside paragraphs need 3:1 against adjacent text under WCAG 1.4.1)
Most accessibility failures come from light gray body copy, faint labels, and light-colored buttons with white text. Fix those three and you'll clear most audits.
One more thing: don't rely on color alone
WCAG 1.4.1 says information can't be conveyed only by color. Red error text passes contrast but still fails if a color-blind user can't distinguish it from normal text without an icon or label.
Pair color with icons, labels, or patterns where the meaning matters.
Top comments (0)