Accessibility

WCAG Color Contrast Guide: Ratios, AA vs AAA, and Examples

Contrast ratios are the single best leading indicator of whether your text will be readable to a wide audience. Learn the formula, the AA and AAA thresholds, how large text and non-text contrast work, and the ratios of common color pairs.

Last reviewed on 2026-10-03

Why contrast matters

Roughly one in twelve men and one in two hundred women experience some form of color vision deficiency. A larger group has reduced contrast sensitivity from age, glare, fatigue, low-quality screens, or harsh sunlight on a phone. Color contrast — the relative brightness of text against its background — is the single design decision that affects all of those readers at once.

The Web Content Accessibility Guidelines (WCAG 2.1 and 2.2) define numeric thresholds so the call is not subjective. The home contrast checker implements those thresholds; this page explains what they mean and where they leave room for judgement.

The contrast ratio

Contrast ratio compares the relative luminance of two colors. The ratio runs from 1:1 (identical colors, invisible) to 21:1 (pure black on pure white). The formula:

ratio = (L_lighter + 0.05) / (L_darker + 0.05)

Where L is the relative luminance of each color. Luminance itself is computed by gamma-correcting each RGB channel and then weighting them — green contributes most, then red, then blue:

L = 0.2126 × R + 0.7152 × G + 0.0722 × B

(Channels are first linearised by reversing the sRGB gamma curve — exact steps below.) The takeaway: blue contributes very little to luminance, which is why pure blue text on a black background tests as poor contrast even though it looks "different." It's the same lightness as the background, just a different hue.

The exact relative luminance formula

For an sRGB color with 8-bit channels (0–255), compute each channel separately, then weight them:

for each channel C in R, G, B:
  c = C / 255
  if c <= 0.04045:  c_lin = c / 12.92
  else:             c_lin = ((c + 0.055) / 1.055) ^ 2.4

L = 0.2126 × R_lin + 0.7152 × G_lin + 0.0722 × B_lin
ratio = (L_lighter + 0.05) / (L_darker + 0.05)

The WCAG 2.x text uses 0.03928 as the threshold instead of the sRGB standard's 0.04045 — it was copied from an older sRGB draft. The difference is harmless: no 8-bit channel value falls between the two (10/255 ≈ 0.0392 and 11/255 ≈ 0.0431), so both versions give identical results for hex colors.

Two more rules from the spec: compare against the threshold without rounding up (4.48:1 fails 4.5:1), and the extra 0.05 in the ratio models ambient flare, which is why the maximum is 21:1 rather than infinity.

The thresholds

LevelNormal textLarge textUI components
WCAG 2.1 / 2.2 AA4.5 : 1 (SC 1.4.3)3 : 1 (SC 1.4.3)3 : 1 (SC 1.4.11)
WCAG 2.1 / 2.2 AAA7 : 1 (SC 1.4.6)4.5 : 1 (SC 1.4.6)—

"Normal text" is anything below 18pt regular or 14pt bold. "Large text" is at or above those thresholds. "UI components" covers actionable graphical elements — focus rings, icons that carry meaning, the visual edges of inputs. Decorative imagery, logotypes, and inactive UI are exempt.

Large text in pixels

WCAG defines large text in points; CSS uses pixels, and 1pt = 4/3 px:

These sizes assume a typical text face. Very thin or decorative fonts read smaller than their nominal size, so give them more contrast, not less.

Non-text contrast (SC 1.4.11)

Added in WCAG 2.1 at level AA, 1.4.11 requires 3:1 against adjacent colors for:

Not covered: disabled components, logos, decorative graphics, and components whose appearance is entirely browser default. A button whose label passes 4.5:1 doesn't also need a 3:1 border if the label alone identifies it; the requirement is that whatever identifies the component and its state is perceivable.

Which level to target

Contrast ratios of common color pairs

Computed with the exact formula above and truncated to two decimals (WCAG does not allow rounding up). "Large / UI" is the 3:1 threshold that applies to large text at AA and to non-text contrast.

TextBackgroundRatioAA normalAA large / UIAAA normal
#FFFFFF#00000021.00 : 1PassPassPass
#000000#FFFF0019.55 : 1PassPassPass
#333333#FFFFFF12.63 : 1PassPassPass
#595959#FFFFFF7.00 : 1PassPassPass
#000000#FFA50010.63 : 1PassPassPass
#FFFFFF#0000FF8.59 : 1PassPassPass
#FFFFFF#0066CC5.56 : 1PassPassFail
#FFFFFF#0080005.13 : 1PassPassFail
#FFFFFF#D32F2F4.97 : 1PassPassFail
#FFFFFF#6C5CE74.85 : 1PassPassFail
#767676#FFFFFF4.54 : 1PassPassFail
#777777#FFFFFF4.47 : 1FailPassFail
#FFFFFF#FF00003.99 : 1FailPassFail
#FFFFFF#007BFF3.97 : 1FailPassFail
#FFFFFF#8080803.94 : 1FailPassFail
#949494#FFFFFF3.03 : 1FailPassFail
#959595#FFFFFF2.99 : 1FailFailFail
#FFFFFF#1DA1F22.82 : 1FailFailFail
#0000FF#0000002.44 : 1FailFailFail
#FFFFFF#FFA5001.97 : 1FailFailFail

Patterns worth remembering: #767676 is the lightest neutral gray that passes AA on white, and #777777 misses by a hair. #595959 is the lightest gray that passes AAA on white. White on pure red and on Bootstrap-style blue #007BFF is large-text only. Saturated oranges and light blues need dark text, not white. Check any other pair in the contrast checker.

A worked example

Take a button: white text on a brand purple. The brand color is #6C5CE7 = rgb(108, 92, 231). Linearise each channel:

R: 108/255 = 0.4235 → 0.1500
G:  92/255 = 0.3608 → 0.1070
B: 231/255 = 0.9059 → 0.7991

L = 0.2126 × 0.1500 + 0.7152 × 0.1070 + 0.0722 × 0.7991 ≈ 0.1661

White is 1.0. Plug into the ratio:

(1.0 + 0.05) / (0.1661 + 0.05) = 4.86 : 1

4.86 passes AA for normal text (≥ 4.5) but fails AAA for normal text (< 7). For a primary button label that's fine. For 12px helper text on the same background, the message is the same — 4.86 still passes AA — but legibility will start to suffer because contrast minimums alone don't account for tiny type, and the margin above 4.5 is thin.

If the same purple is used as text on a white background, the ratio is identical (the formula is symmetric). But if the background changes to a near-white #F2F2F4, the ratio drops to about 4.35 — now failing AA for normal text, passing only for large text. A barely visible tint on the background was enough to cross the line. If the background changes to mid-gray #9999A0, the ratio drops to about 1.72, which fails everything.

Where the rules surprise people

1. Big numbers can hide small text

WCAG considers a button label "large text" only at 18pt regular or 14pt bold. A 14pt label at regular weight is still "normal text" and needs the full 4.5:1 ratio. Designers regularly design at the borderline weight and assume the looser threshold.

2. Disabled controls are exempt

WCAG explicitly excludes inactive UI components from the 3:1 requirement. That doesn't mean disabled buttons should be invisible — it means the contrast rule doesn't trip a violation. Practical advice: keep disabled affordances visible enough that users understand what's interactive when re-enabled.

3. Logos are exempt

Brand marks and "essential" decorative imagery don't have to meet a contrast ratio. A heritage wordmark on its native background is allowed even if it tests poorly. The exemption does not extend to logo-shaped buttons that carry interactive meaning.

4. Placeholder text is text

The default browser styling for ::placeholder often falls below 4.5:1. If the placeholder communicates anything other than "type here," treat it as normal text and check the contrast.

5. Transparency changes everything

The contrast checker assumes solid colors. The moment alpha is introduced — semi-transparent text or a translucent overlay — the visible color depends on what is behind it. Compute the ratio against the resolved color, not the unblended foreground. The RGBA & transparency guide covers the math.

Beyond the ratio

Hitting 4.5:1 is necessary but not sufficient. Several factors influence real-world readability that the formula doesn't capture:

A workflow that catches problems early

  1. Define the palette in tokens, with each pair (text, background) annotated by its tested contrast ratio.
  2. Pick the smallest text size in the system and validate that the lightest text-on-background combination still passes AA.
  3. Verify focus indicators against both their default and active backgrounds — the 3:1 rule applies to the focus ring itself.
  4. Spot-check with the home contrast checker while designing; integrate an automated check (axe-core, Lighthouse) into CI for catching regressions.
  5. Test the result on a real device under bright light, with a color-blindness simulator, and at the smallest text size in the design.

Common mistakes

WCAG 2.2, WCAG 3 and APCA

Where to learn more

The official source is the WCAG 2.2 specification, particularly Success Criterion 1.4.3 (Contrast Minimum), 1.4.6 (Contrast Enhanced) and 1.4.11 (Non-text Contrast). The W3C also publishes detailed Understanding documents that walk through the rationale and exceptions.

Quick reference

Frequently asked questions

What contrast ratio is WCAG AA?

WCAG AA requires at least 4.5:1 for normal text and 3:1 for large text (at least 24px regular or about 18.66px bold). Under success criterion 1.4.11, user interface components and meaningful graphics also need 3:1 against adjacent colors.

What contrast ratio is WCAG AAA?

AAA (success criterion 1.4.6) requires at least 7:1 for normal text and 4.5:1 for large text. AAA adds no stricter requirement for non-text contrast.

What counts as large text in WCAG?

Large text is at least 18 point (24 CSS pixels) at regular weight, or at least 14 point (about 18.66 CSS pixels) when bold. Anything smaller is normal text and needs the 4.5:1 AA ratio.

Is 4.5:1 contrast required for placeholder text?

WCAG has no exemption for placeholder text, so if it is visible text it is held to the same minimum: 4.5:1 for normal-size placeholder text at level AA. Default browser placeholder grays often fail, and automated checkers flag them. Better still, do not rely on placeholders for labels or instructions.

Does color contrast apply to logos?

No. Success criterion 1.4.3 explicitly exempts text that is part of a logo or brand name, and logos are not user interface components under 1.4.11. The exemption does not cover buttons or links that merely use the logo colors.

What is the lightest gray that passes WCAG AA on white?

#767676 is the lightest neutral gray that passes 4.5:1 on white (4.54:1). #777777 is 4.48:1, which fails because WCAG ratios must not be rounded up. For the 3:1 large-text and non-text threshold, the lightest neutral gray is #949494 (3.03:1).

Does white text on red pass WCAG?

White on pure red #FF0000 is 4.00:1. That passes AA only for large text and for UI components, not for normal-size text. A darker red such as #D32F2F reaches 4.98:1 and passes AA for normal text.

Did WCAG 2.2 change the color contrast requirements?

No. WCAG 2.2 became a W3C Recommendation in October 2023 and kept the contrast criteria 1.4.3, 1.4.6 and 1.4.11 unchanged from WCAG 2.1. It added new criteria elsewhere, including focus-related ones.

Is APCA part of WCAG?

No. APCA (Accessible Perceptual Contrast Algorithm) has been explored as a candidate contrast method for WCAG 3, which is still a working draft. It is not normative, and conformance today is measured with the WCAG 2.x contrast ratio.