color-contrast high
color-contrast: Elements must meet minimum contrast ratio
Text-to-background contrast falls under the WCAG 2 AA threshold, so low-vision users and anyone in glare can't read it.
What you see
color-contrast: Elements must meet minimum color contrast ratio thresholds Expected contrast ratio of 4.5:1 Element has insufficient color contrast of 3.1:1 (foreground #999999, background #ffffff, font size 14px)
What’s actually happening
axe-core flags a specific element and prints the measured ratio plus the two colors it sampled. Normal text needs 4.5:1; large text (18.66px bold, or 24px regular and up) and UI components need 3:1. The usual offenders are gray placeholder text, light-gray captions, and white text on a pale brand color. Hover and focus states get missed a lot because the scan only sees the resting state.
Common causes
- Light gray body or helper text on white, e.g. #999 on #fff, which lands around 2.8:1.
- Brand color used for text that was chosen for logos, not legibility — fine as a fill, too weak as foreground.
- White or light text over a photo or gradient where part of the image is bright.
- A color value pulled from a design token that nobody recomputed after a background change.
- Disabled-state styling reused for active controls, dragging real text down to disabled-level contrast.
How to fix it
- Read the ratio axe gives you and aim past the lineThe violation names both hex values and the measured ratio. Plug them into a checker (WebAIM Contrast Checker, or DevTools' color picker, which draws the AA/AAA lines right on the swatch). Target 4.5:1 for body text, 3:1 for large text and icons. Don't stop at exactly 4.5 — antialiasing eats a little.
- Darken the foreground rather than bolding itWeight doesn't change contrast. #767676 on white is the lightest gray that clears 4.5:1; anything lighter fails as normal text. Nudge the text darker (or the background lighter) until the checker passes, then update the design token so it propagates.
- Fix text over images with a scrim or text shadowDrop a semi-opaque overlay between image and text (`background: rgba(0,0,0,0.5)`) or add a solid text shadow. Measure against the lightest pixel the text can sit over, not the average, because the worst spot is what fails.
- Re-scan focus and hover states explicitlyaxe checks the resting state. Force `:hover`/`:focus` in DevTools (Styles pane, `:hov`) and recheck, since a link that passes at rest can fail on hover. Same for placeholder text — it's a frequent silent failure.
Stop it recurring
Bake contrast tokens into the design system and run axe (or pa11y) in CI so a failing color combination breaks the build, not production.
Related errors