/ Accessibility Fixes / Colour Contrast

How to Fix Colour Contrast

Colour contrast failures are the most common accessibility audit finding. They hit two groups hardest: low-vision users who can't distinguish low-contrast text, and anyone reading on a bright screen in sunlight. WCAG sets specific ratios: 4.5:1 for normal text, 3:1 for large text, 3:1 for UI components. The fix is rarely per-element — it's at the design-token level where one colour change cascades site-wide.

1. Audit your contrast

Step 1
Run the Accessibility audit
Run the Accessibility audit with WCAG AA level set. Export findings to CSV. Each row reports: URL, element selector, foreground colour, background colour, calculated contrast ratio, and WCAG level it fails.
Step 2
Group by colour pair
Sort findings by foreground/background pair. You'll often see hundreds of findings collapse to 5-10 unique failing pairs. Those pairs are your design-token problem.

2. The WCAG ratio reference

ContentWCAG AAWCAG AAA
Body text (under 18pt or under 14pt bold)4.5:17:1
Large text (18pt+ or 14pt+ bold)3:14.5:1
UI components (input borders, icons)3:13:1 (no AAA level defined)
Focus indicators3:13:1
Decorative / disabled elementsNo requirementNo requirement

3. Common failing pairs and their fixes

Grey text on white

Most-common failure. Marketing copy "softening" text to #999 or #aaa fails AA badly.

/* FAIL — #999 on #fff = 2.85:1 */
.muted { color: #999; }

/* PASS — #767676 on #fff = 4.54:1 */
.muted { color: #767676; }

Brand colour on white

Many brand colours are designed for impact, not legibility. Light blues, pastels, vibrant pinks often fail.

/* FAIL — #4da6ff on #fff = 2.6:1 */
a { color: #4da6ff; }

/* PASS — #1e6fcc on #fff = 5.1:1 */
a { color: #1e6fcc; }

If your brand colour fails, define an "accessible variant" that's a darker shade for text use while keeping the brand colour for backgrounds and large headings.

Placeholder text

Default browser placeholder colour is often around #a0a0a0 — fails AA. Override:

::placeholder { color: #6b6b6b; opacity: 1; }

Form input borders

Common pattern: #e0e0e0 border on #fff background. Contrast 1.4:1 — fails the 3:1 requirement for UI components.

input { border: 1px solid #767676; } /* 4.5:1 — passes both 3:1 and 4.5:1 */

4. Fix at the design-token level

Step 1
Identify your token system
Most modern sites use design tokens — CSS variables or a Tailwind / Sass colour scale. Find where colour values originate:
/* CSS variables */
:root {
  --text-muted: #999;  /* failing */
}

/* Tailwind config */
colors: {
  gray: { 400: '#9ca3af' }  /* used as text-gray-400 */
}
Step 2
Adjust the token
Change the failing token value to one that passes:
:root {
  --text-muted: #6b6b6b;  /* now 5.7:1 on white */
}
Every usage of var(--text-muted) across the site now passes contrast. One change, site-wide fix.

5. Verify with tools

WebAIM Contrast Checker

webaim.org/resources/contrastchecker — paste foreground and background, get ratio + AA/AAA pass-fail per text size.

Chrome DevTools

Inspect any element → Styles panel → click the colour swatch next to color → contrast ratio shows in the colour picker, with the AA threshold line drawn on the colour gradient.

Browser extensions

WAVE, axe DevTools, Stark — all overlay contrast warnings on the live page so you can spot issues during development.

6. Dark mode

⚠️ Dark mode inverts but doesn't always pass. Common failure: dimming everything to "soft" greys produces light-grey-on-dark-grey, which fails. Test dark mode pairs independently.
:root {
  --bg: #ffffff;
  --text: #1a1a1a;
}

@media (prefers-color-scheme: dark) {
  :root {
    --bg: #1a1a1a;
    --text: #ffffff;  /* keep high contrast in dark mode too */
  }
}

7. Add CI checks

Step 1
Automated contrast checks per PR
Tools: pa11y, axe-core CLI, Lighthouse CI. Run against staging URLs, fail builds on new contrast violations.
# GitHub Actions
- name: Accessibility check
  run: npx pa11y https://staging.yourdomain.com --threshold 0
💡 Defining 2-3 accessible variants per brand colour (bright for backgrounds, dark for text-on-white, light for text-on-dark) up-front prevents the "we need to fix our brand" recurring problem.

♿ Re-run the Accessibility audit

Verify contrast findings are cleared after token fixes.

Run Accessibility Audit →
Related Guides: Accessibility Fixes  ·  Fix Focus Indicators  ·  Fix Alt Text  ·  Accessibility Guide
💬 Got a problem?