Accessibility-First Color Palettes: Designing for WCAG Compliance
Why Start with Accessibility
Many teams pick colors for aesthetics first, then discover during QA that text contrast fails WCAG requirements. Fixing contrast after the fact means either darkening text (which changes the design intent) or reworking the entire palette.
An accessibility-first approach reverses this: start with colors that pass contrast checks, then refine aesthetically within those constraints. The result is a palette that looks good and works for everyone — including the estimated 300 million people worldwide with color vision deficiencies.
WCAG Contrast Requirements
WCAG 2.1 defines two conformance levels:
| Level | Normal Text (< 18pt) | Large Text (≥ 18pt bold or ≥ 24pt) | UI Components |
|---|---|---|---|
| AA | 4.5:1 | 3:1 | 3:1 |
| AAA | 7:1 | 4.5:1 | Not specified |
Normal text includes body copy, labels, and navigation links. Large text includes headings and prominent labels. UI components covers icons, form borders, and focus indicators.
Contrast Ratio Explained
The contrast ratio compares the relative luminance of two colors:
Ratio = (L1 + 0.05) / (L2 + 0.05)
Where L1 is the lighter color and L2 is the darker color. Pure white (#FFFFFF) against pure black (#000000) gives a ratio of 21:1. Two similar grays might give 1.5:1.
Building an Accessible Palette Step by Step
Step 1: Define Your Backgrounds
Start with your surface colors — these are fixed because layouts depend on them.
:root {
--bg-primary: #FFFFFF; /* Light mode main background */
--bg-secondary: #F1F5F9; /* Light mode card background */
}
Step 2: Choose Text Colors That Pass
For each background, calculate the darkest shade needed to reach 4.5:1:
| Background | Min AA Text | Example Passing Color |
|---|---|---|
| #FFFFFF | 4.5:1 | #57534A (ratio: 7.1:1) |
| #F1F5F9 | 4.5:1 | #475569 (ratio: 6.8:1) |
Never rely on the minimum. Choose a text color that exceeds 4.5:1 to provide comfortable reading, not just barely passing.
Step 3: Add Accent Colors with Contrast Verification
Accent colors (for links, buttons, badges) must contrast against their specific background:
:root {
--color-accent: #2563EB; /* Blue for links on white — ratio 4.6:1 ✓ */
--color-success: #16A34A; /* Green for badges — test against background */
--color-warning: #CA8A04; /* Yellow — often fails on white, needs dark text */
}
Yellow warnings are a notorious contrast trap. #CA8A04 on white gives only 2.8:1 — failing AA for normal text. Use a dark text on the yellow background instead:
.badge-warning {
background-color: #FEF3C7; /* Light yellow */
color: #92400E; /* Dark amber text — ratio 7.5:1 ✓ */
border: 1px solid #F59E0B;
}
Dark Mode Accessibility
Dark mode is not simply inverting light mode colors. Contrast requirements still apply:
:root.dark {
--bg-primary: #0F172A;
--bg-secondary: #1E293B;
--text-primary: #F1F5F9; /* Ratio: 15.4:1 ✓ */
--text-secondary: #94A3B8; /* Ratio: 5.6:1 ✓ */
}
Common Dark Mode Mistakes
| Mistake | Why It Fails | Fix |
|---|---|---|
| Pure white (#FFF) text on dark bg | 21:1 ratio creates glare, causes eye strain | Use off-white (#F1F5F9) |
Low-opacity text (rgba(255,255,255,0.5)) | Calculated ratio may fall below 4.5:1 | Test actual rendered color |
| Saturated accent on dark bg | Saturated colors vibrate against dark backgrounds | Desaturate slightly or lighten |
| Same accent as light mode | Blue #2563EB on #0F172A = 2.3:1 ✗ | Use #60A5FA — ratio 5.6:1 ✓ |
Color Blindness Considerations
Approximately 8% of men and 0.5% of women have some form of color vision deficiency. The most common types:
- Deuteranopia (red-green): Cannot distinguish red from green
- Protanopia (red-green): Reduced sensitivity to red light
- Tritanopia (blue-yellow): Cannot distinguish blue from yellow (rare)
Design Rules
- Never use color alone to convey information. Always pair with text, icons, or patterns.
- Avoid red/green for success/error if they share similar luminance. Use shapes or labels as secondary indicators.
- Test your palette with a color blindness simulator. Free tools include Coblis and the built-in Chrome DevTools vision simulation.
Testing Workflow
- During design: Use the Stark plugin (Figma/Sketch) to check contrast in real time
- During development: Run axe-core or Lighthouse accessibility audits
- In CI: Add
pa11yoraccessibility-checkerto your pipeline - Manual spot-check: Use WebAIM Contrast Checker for borderline cases
Key Takeaways
- Start with accessible contrast ratios rather than fixing them later
- AA requires 4.5:1 for normal text, 3:1 for large text and UI components
- Yellow and orange accents frequently fail on light backgrounds — use dark text on light fill instead
- Dark mode needs its own contrast calculations — do not reuse light mode accent colors
- Color should never be the only indicator of meaning — add icons, text, or patterns
- Test with both automated tools and color blindness simulators
Try It Yourself
Build accessible palettes with built-in contrast checking using our Color Palette Generator. It flags WCAG failures in real time as you adjust colors.
Related Guides
- Color Palette Guide — fundamentals of building harmonious palettes
- 60-30-10 Color Rule for Web Design — applying proportion principles to accessible palettes