You're mid-build. Lighthouse flags an accessibility issue. Or a teammate drops a contrast checker screenshot in Slack with a red X on your favorite gray text color. The instinct is to panic and make everything high-contrast black and white. Don't. The rules are simpler than they look.
The Three Numbers
WCAG (Web Content Accessibility Guidelines) defines two conformance levels that matter: AA and AAA. AA is the standard most companies target. AAA is the gold standard.
4.5:1 — Normal Text (AA)
Any text under 18pt (24px) or under 14pt bold (18.66px bold) needs a 4.5:1 contrast ratio against its background. This covers your body text, labels, form inputs, navigation links, and most of your UI. If you remember one number, it's this one.
3:1 — Large Text and UI Components (AA)
Text at 18pt+ (24px+) or 14pt+ bold (18.66px+ bold) gets the relaxed 3:1 ratio. This also applies to UI components: borders on inputs, icon-only buttons, focus indicators, and any non-text visual that conveys meaning. Your heading can be a slightly lighter gray than your body text and still pass.
7:1 — Enhanced Contrast (AAA)
AAA requires 7:1 for normal text and 4.5:1 for large text. Most products don't target AAA globally. But it's the right bar for content-heavy products where users read for extended periods. Think documentation sites, reading apps, or any tool where eye strain is a real concern.
The Common Failures
Almost every contrast failure falls into one of four patterns.
Gray text on white
The most common one. Designers love light gray placeholder text and secondary labels. #A0A0A0 on #FFFFFF is a 2.9:1 ratio. Fails AA. The minimum gray for body text on white is around #757575 (4.6:1). For a more comfortable read, #525252 (7.4:1) hits AAA.
White text on colored buttons
That vibrant blue button with white text? Check it. #FFFFFF on #3B82F6 (Tailwind blue-500) is 3.1:1. Fails for normal-sized button text. You need to darken the blue to around #2563EB (blue-600, 4.6:1) or use larger/bolder text to qualify for the 3:1 threshold.
Light text on dark backgrounds
Dark mode has its own failure pattern. #6B7280 (Tailwind gray-500) on #111827 (gray-900) is 4.2:1. Close but fails for body text. Bump to #9CA3AF (gray-400, 6.3:1) for comfortable readability.
Colored text on colored backgrounds
Green success text on a light green background. Red error text on a light red background. These semantic color pairings fail constantly. The fix: use the dark version of the semantic color for text, not the medium or light version. #166534 (green-800) on #F0FDF4 (green-50) is 7.1:1. Solid.
How to Check
You don't need to memorize the math. The contrast ratio formula uses relative luminance values and it's not something you calculate by hand. Use these tools instead.
Browser DevTools: Chrome, Firefox, and Safari all show contrast ratios in the color picker when inspecting text elements. Chrome even marks pass/fail against WCAG AA and AAA. This is the fastest check.
WebAIM Contrast Checker: Paste two hex codes, get the ratio instantly. Shows pass/fail for all WCAG levels and text sizes. Bookmark it.
Lighthouse: Run an accessibility audit in Chrome DevTools. It flags every contrast failure on the current page with the specific elements and their ratios. Good for catching things you missed.
Figma plugins: Stark and Contrast are popular. They check contrast across your design files before you write any code.
The Quick Reference
/* Minimum contrast ratios — WCAG 2.1 */
AA (standard):
Normal text (<24px): 4.5:1
Large text (≥24px): 3.0:1
Bold text (≥18.66px): 3.0:1
UI components: 3.0:1
AAA (enhanced):
Normal text (<24px): 7.0:1
Large text (≥24px): 4.5:1
/* Safe text colors on #FFFFFF */
Body text: #525252 (7.4:1, AAA)
Secondary: #757575 (4.6:1, AA)
Placeholder: #A3A3A3 (2.6:1, FAILS — use for hints only)
/* Safe text colors on #09090B (dark mode) */
Body text: #D4D4D8 (12.2:1, AAA)
Secondary: #A1A1AA (6.8:1, AA)
Muted: #71717A (4.5:1, AA border)Don't Overcorrect
Accessibility doesn't mean everything has to be maximum contrast. Pure black text on pure white backgrounds (21:1 ratio) actually causes more eye strain for many users than a slightly reduced contrast like #1A1A1A on #FFFFFF (18.5:1). The spec sets minimums, not targets.
Placeholder text and disabled states are explicitly exempt from contrast requirements. They're supposed to look faded. Don't darken your placeholders to 4.5:1. That defeats their visual purpose.
Decorative elements (background patterns, illustrations, non-informational icons) are also exempt. The rules apply to text and UI components that convey meaning. Not to everything on the screen.
The goal is usable, not brutalist. Hit the minimums for body text and interactive elements. Give yourself headroom on content-heavy pages. And check as you build, not at the end when fifty elements fail at once.
Accessibility sounds intimidating. It's three numbers and a contrast checker. You already know more than most.