Color Contrast and Readability: A Practical Guide to WCAG
Β· 6 min read
Every design decision that involves text has a readability consequence. The gap between a foreground color and its background is not a matter of personal taste β it is a measurable quantity with a measurable effect on whether real people can read what you wrote. For someone with low vision, aging eyes, or a screen in direct sunlight, a low-contrast label is not merely harder to read. It may be completely unreadable. The good news is that contrast is one of the few accessibility properties you can calculate exactly and fix before anyone is harmed by it.
What a contrast ratio actually means
A contrast ratio is a single number that compares the relative brightness of two colors. It always runs from 1:1, which means the two colors are identical and produce no contrast at all, up to 21:1, which is pure black text on a pure white background β the maximum physically possible. A ratio of 4.5:1 means the lighter color is 4.5 times as luminant as the darker one.
The calculation is built on relative luminance, a perceptually weighted measure of how much light a color appears to emit. Luminance is not the same as lightness in a color picker. It accounts for the fact that the human eye is far more sensitive to green than to red or blue, so two colors that look equally βbrightβ on a picker may have different luminance values.
You rarely need to run this by hand β contrast checkers do it instantly β but understanding the formula helps explain why two colors that look fine side by side in your design tool can still fail: you are judging perceived hue, not luminance.
The WCAG thresholds
The Web Content Accessibility Guidelines define two conformance levels for contrast: AA, which is the widely adopted legal and industry baseline, and AAA, which is the stricter enhanced target. The thresholds differ based on whether text is considered normal or large.
- Normal text, AA: 4.5:1 minimum. This is the standard target for most body copy, labels, and interface text.
- Normal text, AAA: 7:1 minimum. Substantially higher; appropriate for high-readability contexts like legal documents or medical information.
- Large text, AA: 3:1 minimum. Large text requires less contrast because thicker strokes are inherently more legible.
- Large text, AAA: 4.5:1 minimum. The same threshold as normal text at the AA level.
- UI components and meaningful graphics: 3:1 minimum. This applies to button borders, form field outlines, icons that convey information, and chart lines. It does not apply to decorative artwork or disabled controls.
AA conformance is the realistic goal for almost every public-facing product. AAA is worth pursuing for text-heavy content where readers will spend significant time, but it is impractical to achieve universally β some color combinations simply cannot reach 7:1 while still looking like your brand.
What counts as large text
The distinction between normal and large text has a precise definition in WCAG, and it is based on rendered size, not the value in your CSS file.
Text qualifies as large if it is at least 18 point (approximately 24 CSS pixels) at normal weight, or at least 14 point (approximately 18.66 CSS pixels) when bold. Those numbers come from print typography research and represent the point at which thicker, larger letter forms compensate for lower contrast. One common mistake is to measure the font-size value in the source and forget that a user's browser zoom or a parent element's transform can change the rendered size. When in doubt, treat text as normal-sized and apply the 4.5:1 threshold β it is always safe.
Headings are frequently large text in practice, which is why design systems often allow lighter gray headings that would fail for body copy. Just verify the actual rendered pixel size, because a heading set at 16px bold does not meet the 18.66px bold threshold and must clear 4.5:1 like any normal text.
Why your brand color keeps failing
The most common source of contrast failures is mid-tone color. A medium corporate blue, a muted teal, a warm gray, a dusty rose β these shades sit in the middle of the luminance scale, which means they are neither light enough nor dark enough to create sufficient contrast with either white or black. When placed on a white background, they often land around 2:1 to 3.5:1, comfortably below the 4.5:1 threshold.
The instinctive fix is to add an underline, make the text bold, or increase the font size. Bolding can help at larger sizes by making strokes thicker, but it does not change the contrast ratio itself. The only reliable fix is to change the luminance relationship between the two colors β darken the text, lighten the background, or do both.
The color-alone trap
A related problem is conveying meaning through color without a backup. Red error text on a white page may have a 3:1 ratio β enough for large text but not body copy β and it still communicates nothing to a user who is color-blind or viewing a monochrome display. WCAG requires that color is never the only means of conveying information. Pair color with a text label, an icon, or a border pattern so the message survives without the hue.
Fixing a failing pair
When a checker flags a pair as failing, a systematic approach is faster than guessing at new shades:
- Move lightness, not hue. Most brand guidelines allow flexibility in how dark or light a color is used. Take the failing shade and pull its lightness value down (for text) or up (for backgrounds) until the ratio clears the target. The hue stays the same; only luminance changes.
- Aim past the threshold. A pair that lands at exactly 4.51:1 will fail the moment someone views it on a slightly warm-tinted monitor. Target 5:1 or above for AA compliance so you have a real buffer.
- Test against both light and dark backgrounds. A color that passes on white may fail on a light gray card, and vice versa. Check every surface your text will actually appear on, not just the one you designed for.
- Check focus indicators separately. The 3:1 UI component threshold applies to focus rings and button outlines. A thin one-pixel focus outline in a light color is a very common failure that automated linters often miss.
- Re-run automated checks after every token update. Design token changes propagate across dozens of components at once. A single color value edit can create failures in places that were previously fine. Wire contrast checks into your CI pipeline so regressions surface before they ship.
Contrast accessibility is one of the most tractable parts of inclusive design. Unlike cognitive load or motor accessibility, which require deep user research to get right, contrast has a formula, a threshold, and a checker. There is no ambiguity about whether a given pair passes. Build the habit of checking ratios early β during color palette selection, not during QA β and most failures never reach your users at all.
Try the tool
Put this into practice with our free, no-signup color contrast checker.
Open the Color Contrast CheckerDisclaimer: This article is for general informational purposes only. Figures and recommendations are guidelines, not rules.