Back to blog
Accessibility

WCAG Color Contrast: The Complete Guide to Accessible Color Choices

May 7, 2026 12 min read WCAG contrast ratio

Most designers know color contrast matters for accessibility. Few know exactly why the numbers are what they are, what the difference between AA and AAA actually means in practice, or how to make palette decisions that pass without looking washed-out and clinical. This guide covers all of it — the math behind WCAG contrast ratios, the practical difference between compliance levels, the mistakes that cause most failures, and how to build accessible palettes that still look good.

Whether you're checking a single color pair or auditing an entire design system, the principles are the same. Let's start at the foundation.

What WCAG Contrast Ratios Actually Mean

WCAG stands for Web Content Accessibility Guidelines — the international standard for web accessibility published by the W3C. The contrast requirements exist for one reason: a significant portion of your users have vision impairments that make low-contrast text difficult or impossible to read. Roughly 300 million people worldwide have some form of color vision deficiency; billions more read in suboptimal conditions — bright sun, old screens, small devices, tired eyes at 11pm.

The WCAG contrast ratio is a number between 1:1 and 21:1 that describes the luminance difference between two colors. A ratio of 1:1 means the colors are identical — no contrast at all. A ratio of 21:1 is maximum contrast: pure black on pure white. Here's the math:

Contrast Ratio = (L1 + 0.05) / (L2 + 0.05)
Where L1 is the relative luminance of the lighter color, L2 is the relative luminance of the darker color.
Relative luminance is calculated from linearized RGB values using the WCAG formula.

Luminance is not the same as brightness, lightness, or perceived intensity. It's a specific measure derived from how human vision responds to different wavelengths of light — red, green, and blue channels contribute differently, weighted to match the eye's sensitivity curve. This is why a bright red and a bright green can have completely different contrast ratios against the same background even if they appear equally "bright" in isolation.

The practical implication: you cannot eyeball contrast ratios reliably. A pale yellow on white looks obviously low-contrast. A medium blue on white can fool you — it feels fine at a glance but fails WCAG AA. The only reliable method is measurement. That's what a color contrast checker does: it calculates the actual luminance of each color and returns the exact ratio.

AA vs AAA: The Two WCAG Conformance Levels Explained

WCAG defines two conformance levels for contrast: Level AA (the legal minimum in most jurisdictions) and Level AAA (the highest standard, used primarily for critical content). Understanding the difference — and when each applies — is essential for making informed decisions about your palette.

Level Normal Text Large Text UI Components Required for
AA 4.5:1 3:1 3:1 Legal compliance (ADA, EN 301 549, etc.)
AAA 7:1 4.5:1 Not specified Critical content, medical, government

What Counts as "Large Text"?

Large text is defined as 18px or larger in regular weight, or 14px or larger in bold (700 weight). This threshold matters because larger text is inherently easier to read at lower contrast — the letterforms are bigger, so the eye can resolve them with less luminance difference. Most body copy is normal text (requiring 4.5:1 at AA). Headlines at 32px or larger are large text (requiring 3:1 at AA).

What Counts as "UI Components"?

UI components include interactive elements — buttons, form inputs, checkboxes, radio buttons, sliders, and focus indicators. The 3:1 ratio applies to the boundary of the component against its background. A gray button on a white background must have its border or fill achieve 3:1 against white. This catches the common mistake of using a very light gray button that's technically visible but functionally invisible to users with low contrast sensitivity.

Should You Target AA or AAA?

Target AA as your baseline — it's legally required in many contexts and covers the vast majority of accessibility needs. Aim for AAA where you can achieve it without compromising your design — it's a better experience for everyone, not just users with disabilities. Older users with declining contrast sensitivity (which affects virtually everyone over 60) benefit significantly from higher contrast ratios even when they'd never identify as "accessibility users."

The practical design approach: try to hit 4.5:1+ for all body text and 3:1+ for large text and UI elements, then check whether pushing higher would require compromising your brand palette in ways that hurt the overall design. Often you can reach 5:1 or 6:1 with small color adjustments that are invisible in everyday use.

Reading Real Contrast Ratios: What the Numbers Look Like

Abstract numbers are hard to internalize. Here are real contrast examples across the range — from clearly failing to exceeding AAA — so you can calibrate your eye against the standard.

Ratio 1.8:1 — Fails Everything

Sample
The quick brown fox jumps over the lazy dog.
Light gray on near-white: the most common failure.
Normal text
This is what "subtle" gray text looks like.
Placeholder text at this contrast is unreadable for many users.
1.8:1
#c0c0c0 on #f5f5f5
Fails AA Normal Fails AA Large Fails AAA

Ratio 3.2:1 — Passes AA Large Text Only

Headline (passes)
Large headline text
Body text at this ratio fails AA.
Body copy (fails)
This body text at 17px looks fine at a glance but fails WCAG AA for normal text.
3.2:1
#767676 on #ffffff
Fails AA Normal Passes AA Large Fails AAA

Ratio 4.6:1 — Passes WCAG AA

Normal text
This body text passes AA. Comfortable for most users, including many with low vision.
Large text
Headline also passes AA.
4.6:1
#595959 on #ffffff
Passes AA Normal Passes AA Large Fails AAA

Ratio 7.5:1 — Passes WCAG AAA

Normal text
High-contrast body text. Exceeds AAA — accessible to the widest possible range of users, including most low-vision conditions.
Dark mode
Dark mode body text at comparable contrast.
7.5:1
#333333 on #ffffff
Passes AA Normal Passes AA Large Passes AAA
Free tool
Check any color pair instantly
Paste two hex codes. Get the contrast ratio, AA/AAA pass/fail status, and suggestions for accessible alternatives — in seconds. No login required.
Open Contrast Checker →

Common Contrast Mistakes (And How to Fix Them)

These are the failures that show up on almost every accessibility audit. Recognizing the patterns is faster than running every color pair through a checker every time.

Mistake 1
Light gray placeholder text on white inputs

The classic offender. Placeholder text in form inputs is frequently styled in a very light gray — #aaa, #bbb, #ccc — on white backgrounds, achieving ratios of 1.5:1 to 2.5:1. It looks "subtle and elegant" in a Figma mockup at 200% zoom. At actual size on a phone in daylight, it's invisible. Fix: use #767676 minimum on white for any text, including placeholders. If the design requires lighter placeholder text, use a slightly off-white input background to increase the ratio.

Mistake 2
Brand colors used for body text without checking

Designers pick a beautiful mid-tone brand color — a warm amber, a medium teal, a muted sage — and use it for body copy or subheadings. Brand colors are calibrated for logo and accent use, not body text. A medium amber (#e8a44a) on white achieves roughly 2.8:1 — it fails AA for normal text. Fix: use brand colors for headlines only where they qualify as "large text," or create a darker shade specifically for body copy use. A 60% darkened version of your brand hue usually passes while remaining on-brand.

Mistake 3
White text on medium-saturation color backgrounds

White text on brand-colored buttons is one of the most common contrast failures. A medium blue (#4a90d9), medium green (#5cb85c), or medium purple (#9b59b6) paired with white text achieves ratios in the 3:1–4:1 range — passing for large text, failing for normal text. Most button labels are small enough to be "normal text." Fix: darken the background until you reach 4.5:1, or use dark text if the background is light enough. Check: #1a5fa8 on white is 7.2:1. #4a90d9 on white is 3.1:1. Same hue, very different result.

Mistake 4
Relying on color alone to convey information

This isn't technically a contrast mistake, but it's adjacent to contrast compliance and equally important: using color as the only differentiator between states. A red error state and a green success state that differ only in hue are indistinguishable to the 8% of men with red-green color blindness. Fix: always pair color with a secondary signal — an icon, a text label, a pattern, or a shape change. Contrast ratio compliance doesn't solve this problem; only redundant coding does.

Mistake 5
Not testing dark mode separately

A palette that passes in light mode can fail in dark mode if dark mode uses a direct color inversion or a different surface color than expected. Dark mode text on dark surfaces has different luminance relationships than the same colors in light mode. Fix: treat dark mode as a separate color system that needs its own contrast checks. A common shortcut — cranking all text to near-white (#e8e6e3) on deep charcoal (#08080a) — achieves ratios above 13:1, which is comfortable and exceeds AAA. Don't assume passing in one mode means passing in both.

How to Check Contrast Ratios: The Right Workflow

You don't need to calculate luminance by hand. Here's the efficient workflow for checking contrast during design, before shipping, and during audits.

During Design (Figma / Sketch)

Most modern design tools have built-in contrast checking. In Figma, select a text layer → open the Inspect panel → contrast ratio appears under the color section. This is fine for spot-checking individual elements but slow for systematic audits. Figma plugins like Contrast or A11y - Color Contrast Checker can flag all failing elements at once.

Spot-Checking Specific Color Pairs

For checking any two hex codes instantly — especially when evaluating palette options or debugging a specific element — a dedicated color contrast checker is faster than any design tool. Paste the foreground and background hex codes, get the ratio and compliance status immediately. Forma's Contrast Checker also suggests adjusted colors that pass if the current pair fails.

Full-Page Accessibility Audits

For deployed pages, browser DevTools include accessibility auditing. In Chrome: open DevTools → Lighthouse → Accessibility audit. This catches contrast failures on actual rendered pages, including dynamic states (hover, focus, disabled) that static tools miss. Axe DevTools (browser extension) provides more granular contrast reporting with exact element references.

Before Every Deploy

Run automated contrast checks as part of your CI pipeline using tools like axe-core (JavaScript) or pa11y. These catch regressions where a CSS change inadvertently drops a passing color pair below threshold. A single missed change to a CSS variable can break contrast site-wide — automation is the only reliable catch at scale.

The 10-second rule

If you can read a line of text comfortably in 10 seconds without squinting, it might still fail WCAG. The problem isn't how text looks to you — it's how it looks to someone with vision impairment, on an older screen, in outdoor light. Always measure, never assume. Your eyes are not a reliable instrument for contrast at the margins.

Accessible Color Palette Tips for Designers

Accessibility doesn't mean choosing safe, boring colors. It means knowing how to work with the constraints. These principles produce palettes that are both distinctive and compliant.

Build a Tonal Scale for Every Hue

For each brand hue, define a full tonal scale — light to dark, typically 9–11 steps. Assign specific steps for specific purposes: background fills, border colors, body text, UI components. This prevents ad hoc color choices that haven't been contrast-checked and makes compliance predictable rather than reactive. Tools like Palette Generator can generate accessible tonal scales from a seed color, automatically checking contrast at each step.

Tip
The 50/500/900 convention

In many design systems, 50-level shades are near-white backgrounds, 500-level shades are the "true" brand color at medium saturation, and 900-level shades are near-black usable for text. The rule of thumb: 500-level colors on white rarely pass for body text; 700+ usually does. Build your palette so text use cases pull from the darker end of the scale.

Test Brand Colors in Dark Mode Early

Most brand colors that work as text on white will also work as accent colors on dark backgrounds — because the relationship is inverted. A color that's "too light" for white backgrounds often achieves strong contrast on dark surfaces. Design the dark mode palette from the same hue family and verify both directions independently. Don't derive dark mode colors by inverting light mode — derive them by choosing the tonal step that achieves your target ratio on each background.

Use Desaturation Strategically

High-saturation colors look vibrant but often fail contrast requirements because their luminance sits in the middle range. A fully saturated red (#ff0000) achieves about 4:1 on white — technically passing AA for normal text, but barely. Slightly desaturating and darkening (#c0392b) keeps the red hue while pushing contrast to 5.1:1. The human eye is less sensitive to saturation differences than to hue differences — desaturating brand colors for text use cases is often invisible to most viewers.

Reserve Mid-Tone Colors for Decorative Use

Mid-tone colors — anything roughly in the 40–60% luminance range — rarely pass contrast requirements against either white or black backgrounds. They're the colors that look beautiful in brand illustrations, background swashes, or chart fills but fail as text or UI element colors. Plan for this: reserve your mid-tone brand colors for decorative elements and use darker or lighter shades for anything that carries semantic meaning or needs to be read.

Always Check Focus Indicators

Focus indicators — the visible outline that appears when a keyboard user tabs to an element — are subject to WCAG 2.2's enhanced focus visibility requirements. The focus indicator must achieve a 3:1 contrast ratio against both the element it's on and the adjacent colors. Many designs suppress the browser default focus outline and replace it with a brand-colored ring that fails this threshold. Fix: use an offset focus ring in a high-contrast color (pure white on dark backgrounds, near-black on light backgrounds) that works independent of the focused element's color.

The color palette link

Your contrast decisions don't exist in isolation — they're downstream of your palette structure. If you haven't defined a systematic tonal scale yet, start with the Color Palette Generator: it generates accessible tonal scales from any brand color, pre-checked for contrast at each step. That gives you a foundation where contrast compliance is built in, not bolted on.

The Contrast Checker Workflow: Start to Ship

Here's the practical end-to-end process for a design system that stays compliant without slowing you down.

  1. Define your palette with tonal scales — use a tool that pre-checks each step's contrast on white and black backgrounds. Know before you design which steps are safe for text use.
  2. Assign semantic roles to palette steps — "text-primary" is step 900, "text-muted" is step 700, "border" is step 200. Never use ad hoc colors outside the scale for anything that has a contrast requirement.
  3. Spot-check with a contrast checker during design — any time you use a color outside its assigned role, or on an unusual background, check the pair immediately with a color contrast checker.
  4. Audit before ship — run Lighthouse or axe on every new page before it goes to production. Fix any failures before they become live regressions.
  5. Automate in CI — add pa11y or axe-core to your build pipeline. Catch regressions before they reach staging.

Done correctly, accessibility compliance is not a tax you pay at the end of the project — it's a property of the palette you build at the start. When your semantic color assignments are correct and your tonal scale is contrast-safe, individual component decisions become automatic.

The bottom line

A passing WCAG contrast ratio is not a badge of boring — it's evidence that your color decisions were deliberate. The most distinctive design systems in existence (Linear, Vercel, Stripe) all pass AA with room to spare. High contrast is what makes dark mode feel premium, not washed out. The constraint forces you toward color choices with real luminance depth. Work with it, not around it.

Check your palette now

Build a design that passes and looks good.

Describe your brand in plain text. Forma generates a full landing page with an accessible color palette, correct contrast on all text elements, and a design system that doesn't look like everyone else's.

Try Forma free →
Stay sharp

Design insights worth reading.

No noise. Patterns that separate distinctive design from forgettable output — straight to your inbox.