WCAG Color Contrast: Building Accessible Color Systems
How contrast ratio requirements work, the difference between WCAG AA and AAA, and practical strategies for designing accessible color systems.
Why Contrast Matters
Approximately 8% of men and 0.5% of women have some form of color vision deficiency. Many more people have low vision, are in bright sunlight, or use older screens with limited dynamic range. Sufficient color contrast ensures text is readable regardless of these conditions.
The Web Content Accessibility Guidelines (WCAG) define minimum contrast ratios as part of their Success Criteria under 1.4.3 Contrast (Minimum) and 1.4.6 Contrast (Enhanced).
What Is a Contrast Ratio?
Contrast ratio compares the relative luminance of two colors. Luminance is a measure of perceived brightness, accounting for how the human eye is more sensitive to green than red or blue.
Contrast ratio formula
Contrast Ratio = (L1 + 0.05) / (L2 + 0.05) Where L1 = relative luminance of lighter color L2 = relative luminance of darker color Range: 1:1 (no contrast) to 21:1 (black on white)WCAG AA vs AAA
Level AA (minimum legal standard in many jurisdictions)
- Normal text (under 18pt, or 14pt bold): 4.5:1 minimum
- Large text (18pt+ or 14pt bold+): 3:1 minimum
- UI components and graphics: 3:1 against adjacent colors
Level AAA (enhanced)
- Normal text: 7:1 minimum
- Large text: 4.5:1 minimum
AAA is aspirational — not all content can meet AAA without sacrificing design quality. However, meeting AAA for body text significantly improves legibility for all users, not just those with disabilities.
Calculating Relative Luminance
function relativeLuminance(r, g, b) {
const sRGB = [r, g, b].map(c => {
c /= 255;
return c <= 0.03928 ? c / 12.92 : ((c + 0.055) / 1.055) ** 2.4;
});
return 0.2126 * sRGB[0] + 0.7152 * sRGB[1] + 0.0722 * sRGB[2];
}
function contrastRatio(color1, color2) {
const l1 = relativeLuminance(...color1);
const l2 = relativeLuminance(...color2);
const lighter = Math.max(l1, l2);
const darker = Math.min(l1, l2);
return (lighter + 0.05) / (darker + 0.05);
}Common Failures
- Light gray on white: Very popular in flat design — often fails AA.
#999on white is only 2.85:1 - Brand colors on white backgrounds: Saturated colors (yellow, light blue) often have luminance too close to white
- Placeholder text: By convention styled lighter than input text — frequently below 3:1
- Disabled states: WCAG exempts disabled elements, but consider users who can't tell a field is disabled
- Text on images/gradients: The contrast varies across the image — test the worst-case area
Building an Accessible Palette
Rather than checking colors after the fact, design your palette with contrast in mind:
- Choose a base text color with luminance near 0 (e.g.,
#1a1a1a) - Generate tints and shades of your brand color, testing each against your backgrounds
- Reserve your lightest brand shades for large text or decorative use only
- Create a secondary "accessible" set of your colors that meet AA even for small text
WCAG 3.0 and APCA
The next version of WCAG introduces the Advanced Perceptual Contrast Algorithm (APCA), which better accounts for font size, weight, and spatial frequency. It uses a different scale (Lc values instead of ratios) and gives more accurate results for non-black-on-white combinations like blue on dark gray. APCA is not yet a formal standard but is worth monitoring for future-proofing.
Try it yourself
Check color contrast ratios against WCAG AA and AAA standards instantly in your browser.
Open Contrast Checker →