How to check color contrast for WCAG (without opening DevTools)
The most common accessibility failure on the web is not missing alt text or broken keyboard navigation. It is text that blends into its background. Designers who work at full zoom on calibrated monitors miss it. Developers who copy a color value from a design file miss it. QA passes it because it looks fine.
Then someone using a cheaper display, or with reduced contrast sensitivity, opens your page and cannot read it.
Here’s the upside: contrast is one of the few accessibility checks with no judgment call attached. Either the ratio passes or it doesn’t. You don’t have to argue about it in a design review.
The WCAG contrast ratios, explained
WCAG 2.1 (and 2.2) defines contrast requirements in Level AA, which is the standard most compliance requirements reference:
- Normal text (below 18pt / 24px regular, or 14pt / 19px bold): minimum 4.5:1 contrast ratio
- Large text (18pt / 24px regular or larger, 14pt / 19px bold or larger): minimum 3:1 contrast ratio
- UI components and graphical elements: minimum 3:1 against adjacent colors
Level AAA tightens normal text to 7:1 and large text to 4.5:1. Unless you are building for a context with a specific AAA requirement, AA is the target.
The contrast ratio is calculated from the relative luminance of the two colors — a perceptual measure that accounts for how the eye processes different wavelengths. A ratio of 1:1 means no contrast (same color). A ratio of 21:1 is black on white — the maximum possible.
A ratio of 3.8:1 fails the 4.5:1 threshold for normal text no matter how fine it looks on your monitor. The math doesn’t care about your display.
Why “subtle” gray text almost always fails
Light gray text on a white or near-white background is everywhere in modern UI. It looks refined, it reads as visual hierarchy, and it fails WCAG more often than any other color combination I run into.
Here’s the usual culprit:
/* Common "secondary" text pattern */
.secondary-text {
color: #9ca3af; /* Tailwind gray-400 */
background: #ffffff; /* white */
}
/* Contrast ratio: ~2.5:1 — fails 4.5:1 requirement */
Tailwind’s gray-500 (#6b7280) on white sits at about 4.8:1, so it clears 4.5:1 by a hair. That margin is thin enough that any tint, opacity, or off-white background can push it under. If you want comfortable headroom, gray-600 (#4b5563) lands around 7.6:1 and stops being a question.
The same failure appears with:
- Placeholder text in form inputs (extremely common)
- Disabled button labels
- Caption and helper text below form fields
- Footer links and legal copy
- Icon-only buttons with light icon colors
How to actually check contrast
Option 1: Browser DevTools
Chrome and Firefox both display a contrast ratio in the color picker when you inspect an element’s color or background-color. It shows the ratio and a pass/fail indicator. Useful but slow — you have to inspect each element individually, switch contexts, and re-check when colors change.
Option 2: Dedicated tools
- WebAIM Contrast Checker — paste two hex values, get immediate pass/fail for AA and AAA at both text sizes. Fast for spot checks.
- Figma plugins like Contrast or Stark — useful during design, not deployment.
- axe DevTools browser extension — automated scan that catches contrast failures across the page.
Option 3: automate the rest of the WCAG pass
Contrast is best handled by the dedicated tools above — your browser’s color picker for spot checks, the WebAIM Contrast Checker for exact pairs, or axe DevTools for a full-page sweep. PxGuard deliberately doesn’t compute contrast (a reliable ratio needs the exact text-over-background pairing those tools specialize in); instead it flags the other WCAG failures that are just as common and harder to eyeball — missing accessible names, keyboard and focus order, ARIA roles, heading structure, and missing alt text — right on the page. Run axe (or WebAIM) for contrast and PxGuard for the rest.
Pair this with the broader 5-minute WCAG check workflow to cover the other common accessibility failures alongside contrast.
Common offenders to check first
When you are doing a contrast audit, start here:
- Body copy on near-white backgrounds — check the base text color at your lightest background, not just white
- Secondary/muted text — any class named
text-muted,text-secondary,caption, or similar - Placeholder text — browsers often render this at reduced opacity on top of the CSS color value, making it even lighter than expected
- Link text on colored backgrounds — especially common in call-to-action sections with colored backgrounds
- Text inside badges and labels — small containers with background colors often get light text that fails at small sizes
- Ghost button text — outlined buttons on light backgrounds frequently sit close to the failure threshold
/* Example: ghost button that fails */
.button-ghost {
color: #94a3b8; /* too light */
border: 1px solid #94a3b8;
background: transparent;
}
/* Fixed: darken the text/border color */
.button-ghost {
color: #475569; /* passes 4.5:1 on white */
border: 1px solid #475569;
background: transparent;
}
What about dark mode?
Dark mode does not automatically solve contrast. It introduces its own common failures:
- Bright saturated text (like pure
#00ff00green) on dark backgrounds often has too much luminance difference — not a WCAG failure, but can cause halation effects for users with certain visual conditions - Light grays on dark gray backgrounds replicate the same low-contrast pattern from light mode, just inverted
- Semi-transparent overlays over images or gradients are unpredictable in both modes
The same 4.5:1 rule applies in dark mode. Check it separately — do not assume that inverting your palette automatically passes.
Catch it before someone has to report it
Contrast failures reach production for one boring reason: nothing in the normal workflow flags them. No linter, no console warning, no failing test. They surface when a user complains, or when an audit finally runs months later.
So make the check cheap enough that it happens by default. Glance at the contrast on any new component with text before it ships. That one habit kills off a whole class of bug that’s awkward to explain after the fact and, for some users, genuinely hard to work around.
If you want to check keyboard accessibility alongside contrast, the posts on ARIA labels for icon buttons and positive tabindex issues cover the next most common violations.
See it on your own pages
PxGuard is a free Chrome extension. Inspect spacing, typography, and accessibility in seconds.
Install Free