How to Fix Color Contrast Accessibility Issues

Published Jan 17, 2026 7 min read

If your text doesn't have enough contrast against its background, some of your visitors literally can't read it. I'm talking about people with low vision, color blindness, or honestly, anyone squinting at their phone in the sun. The good news? Contrast issues are some of the easiest accessibility problems to fix, and I'll walk you through exactly how to do it.

What Is Color Contrast?

Color contrast is the difference in brightness between two colors, measured as a ratio. Black text on white? That's 21:1, the maximum. White text on white? That's 1:1, which means zero contrast (and obviously, nobody can read it).

Your eyes need a certain level of contrast to tell text apart from its background. And if you've got low vision (cataracts, glaucoma, macular degeneration), you need even more. That's why WCAG sets specific minimum ratios, so your content stays readable for the widest possible audience.

This requirement is defined in WCAG Success Criterion 1.4.3 (Contrast Minimum) at Level AA, and SC 1.4.6 (Enhanced Contrast) at Level AAA.

WCAG Contrast Requirements

WCAG 2.2 defines two levels of contrast compliance. You'll almost certainly want to target Level AA. Here's what that requires:

Element AA Minimum AAA Enhanced
Normal text (under 18pt / 14pt bold) 4.5:1 7:1
Large text (18pt+ / 14pt+ bold) 3:1 4.5:1
UI components & graphical objects (SC 1.4.11) 3:1 N/A

What Counts as “Large Text”?

Large text is defined as 18pt (24px) or larger for regular weight, or 14pt (approximately 18.66px) or larger for bold weight. This corresponds roughly to CSS font-size: 24px or font-size: 18.66px; font-weight: bold.

Common Contrast Mistakes

After scanning thousands of websites, these are the contrast problems I see come up again and again:

1. Light Gray Text on White Backgrounds

This is the single most common contrast failure. Designers often use light gray (#999 or lighter) for "secondary" text like captions, timestamps, or helper text. Gray (#999999) on white (#FFFFFF) has a contrast ratio of only 2.85:1, well below the 4.5:1 minimum.

2. Placeholder Text with Poor Contrast

Default browser placeholder text is usually way too light. Technically, placeholder text has a partial exemption since it's not "required" content, but your users still need to read it. I'd recommend at least #767676 on white to hit 4.5:1.

3. Text Over Images Without Overlays

You know those hero sections with text slapped directly on a background image? They almost always fail contrast because parts of the image blend right into the text. Without a semi-transparent overlay or text shadow, you're rolling the dice on readability.

4. Brand Colors That Don't Meet Requirements

Here's one that catches a lot of people off guard: your brand colors might not be accessible. That bright orange or light blue looks great in a logo, but as heading text on a white background? It probably doesn't hit 4.5:1.

5. Disabled State & Low-Priority UI

Disabled buttons and "muted" elements tend to get styled with barely-there contrast. Disabled controls technically have a WCAG exemption, but don't forget that surrounding labels and status text do not.

Step-by-Step Fixes

Step 1: Audit Your Current Colors

First, run a free accessibility scan to find every contrast failure on your page. The scanner flags each element with its current ratio and the required ratio, so you'll know exactly what needs to change.

Step 2: Adjust Text Colors

For each failing element, you'll either darken the text or lighten the background until you hit the required ratio. Here are some safe go-to choices for body text on white:

  • #333333 on white = 12.63:1 (passes AA and AAA)
  • #595959 on white = 7.0:1 (passes AA and AAA)
  • #767676 on white = 4.54:1 (just passes AA)
/* Before: fails AA */
.caption { color: #aaaaaa; }  /* 2.32:1 on white */

/* After: passes AA */
.caption { color: #767676; }  /* 4.54:1 on white */

Step 3: Fix Text on Images

Add a semi-transparent overlay between the image and the text:

.hero {
  position: relative;
  background-image: url('hero.jpg');
}
.hero::before {
  content: '';
  position: absolute;
  inset: 0;
  background: rgba(0, 0, 0, 0.6);
}
.hero-content {
  position: relative; /* sits above overlay */
  color: #ffffff;
}

Step 4: Update Your Design System

This is the step most people skip, but it's how you prevent contrast failures from creeping back in. Bake minimum ratios into your design tokens, and document which backgrounds each text color can be used on:

:root {
  --text-primary: #1a1a1a;     /* 16.75:1 on white */
  --text-secondary: #595959;   /* 7.0:1 on white */
  --text-muted: #767676;       /* 4.54:1 on white, AA minimum */
}

Step 5: Re-scan and Verify

Once you've made your changes, run another scan to make sure everything's clean. Fair warning: contrast fixes can have cascading effects. Change one background color and you might create new failures in other elements, so always verify.

Testing Your Contrast

Beyond automated scanning, here are a few ways I'd recommend verifying your contrast:

  • Browser DevTools: Chrome, Firefox, and Edge all show contrast ratios in the color picker when inspecting elements. In Chrome, right-click any text, choose "Inspect," then click the color swatch next to the color property. You'll see the ratio right there with a pass/fail indicator.
  • Our free scanner: Run a scan to catch all contrast issues at once across your entire page.
  • WebAIM Contrast Checker: A quick web-based tool where you punch in two hex values and instantly see the ratio. I use this one all the time when I'm choosing colors during design.
  • Design tools: Figma has the "Stark" and "A11y - Color Contrast Checker" plugins. Sketch and Adobe XD have similar options. These let you catch failures before any code gets written.
  • Manual check: Try reading your site at arm's length, or view it on a phone in direct sunlight. If you're squinting, your users are too.

If you're running a WordPress site, most of these same principles apply, but there are also plugin-based solutions that can automate contrast checking within your theme. I wrote about that in my guide to WordPress ADA compliance.

One thing I want to stress: don't just check your homepage. Run scans on your interior pages too. Product pages, blog posts, checkout flows, contact forms. Contrast problems tend to hide in the places you look at least often. And while you're auditing, you might also want to verify that your images have proper alt text, since color contrast and missing alt text are the two most common WCAG failures I see.

Pro Tip

Check contrast during design, not after you've written the CSS. Trust me, it's way cheaper to tweak a color in Figma than to rework stylesheets across your entire site. Make contrast checking part of your design review and you'll save yourself a ton of headaches.

Dark Mode Contrast

Dark mode is everywhere now. Most operating systems and browsers support it, and users expect it. But here's the thing: dark mode introduces a whole new set of contrast problems that you might not have thought about.

When you flip to a dark background, all the color math changes. That nice dark gray text you carefully chose for your light theme? It's going to be invisible on a dark background. You need a separate set of color tokens for dark mode, and each one has to be checked against your dark backgrounds.

Here are some safe dark-mode text colors on a #1a1a1a background:

  • #ffffff on #1a1a1a = 16.75:1 (passes AA and AAA)
  • #e0e0e0 on #1a1a1a = 12.65:1 (passes AA and AAA)
  • #a3a3a3 on #1a1a1a = 5.92:1 (passes AA for normal text)
  • #8a8a8a on #1a1a1a = 4.08:1 (fails AA for normal text, passes for large text only)
/* Light mode tokens */
:root {
  --bg-primary: #ffffff;
  --text-primary: #1a1a1a;     /* 16.75:1 */
  --text-secondary: #595959;   /* 7.0:1 */
}

/* Dark mode tokens */
@media (prefers-color-scheme: dark) {
  :root {
    --bg-primary: #1a1a1a;
    --text-primary: #f0f0f0;   /* 14.67:1 */
    --text-secondary: #a3a3a3; /* 5.92:1 */
  }
}

A common mistake I see: people set up dark mode with pure white text (#ffffff) on a pure black background (#000000). That's 21:1, which technically passes. But all that contrast actually causes eye strain for a lot of people, especially when reading long blocks of text. It's better to use an off-white like #f0f0f0 on a dark gray like #1a1a1a. Still passes with plenty of room to spare, and it's much easier on the eyes.

Also, don't forget about links in dark mode. Your blue links that looked great on white might blend right into a dark background. Check every interactive element in both modes. If you're not sure where to start with all these requirements, my explanation of WCAG covers the full standard and how contrast fits into the bigger picture.

Next Steps

Color contrast is honestly one of the easiest accessibility wins you can get. Scan your website now to find every contrast issue, then follow the steps above to knock them out. If you want to go deeper on visual accessibility, check out my complete color contrast guide, or take a look at the ADA compliance checklist for the full picture.

Check Your Color Contrast Now

Run a free scan and I'll show you every contrast issue on your site. It takes about 60 seconds.

Run Free Scan More Articles