Check contrast. Fix it. Share it.

WCAG 2.2 + APCA

Understanding WCAG Contrast Levels

AAMinimum Compliance

Requires a contrast ratio of at least 4.5:1 for normal text and 3:1 for large text (18px bold or 24px regular). This is the standard most websites and apps are expected to meet for legal and accessibility compliance.

AAAEnhanced Accessibility

Requires a contrast ratio of at least 7:1 for normal text and 4.5:1 for large text. This is the highest WCAG level, recommended for critical content and long-form reading. Not always required for full conformance, but significantly improves readability.

APCANext-Generation Model

The Accessible Perceptual Contrast Algorithm is the proposed replacement for WCAG 2.x contrast math. Instead of a single ratio, APCA produces a lightness contrast (Lc) value that accounts for polarity (light-on-dark vs. dark-on-light) and correlates more closely with perceived readability. Minimum Lc values depend on font size and weight.

Contrast standards reference: WCAG 2.x and APCA thresholds, formulas, disagreements

The checker above computes WCAG 2.x ratio and APCA Lc for any color pair. The reference below covers the math behind both algorithms, every published threshold, the disagreement zones where the two metrics give opposite verdicts, and the legal landscape that decides which one applies to your project.

Algorithm summary

PropertyWCAG 2.xAPCA
Spec statusW3C Recommendation since WCAG 2.0 (2008); current at 2.2 (Oct 2023)Candidate algorithm in WCAG 3.0 working draft
AuthorW3C Web Content Accessibility Guidelines Working GroupAndrew Somers, Inclusive Reading Technologies
OutputContrast ratio, 1:1 to 21:1Signed Lc value, roughly −108 to +106
Polarity awareNo (same number whether dark on light or light on dark)Yes (sign encodes polarity)
Font size awareBinary (normal vs “large”)Continuous (size and weight shift the threshold)
Color spacesRGB with piecewise gamma decodesRGB with soft clamp on near-black values
Reference implementationFormula is the spec; many librariesapca-w3 (npm), pinned to a published commit
Legal bindingEAA, Section 508, ADA Title II all reference WCAG 2.xNone

WCAG 2.x AA and AAA thresholds

Content typeLevel AALevel AAA
Normal text (under 18pt regular, under 14pt bold)4.5:17:1
Large text (18pt+ regular, 14pt+ bold)3:14.5:1
UI components (button outlines, form borders, focus rings)3:1n/a
Graphical objects conveying information3:1n/a
Logo or brand-mark textExemptExempt
Decorative or inactive UINo floorNo floor

CSS pixel equivalents at 96 DPI: 18pt is about 24px regular; 14pt bold is about 18.66px bold. “Large” requires both size and weight to clear the bar at once. SC 1.4.3 covers text contrast. SC 1.4.11 covers non-text contrast. SC 2.4.11, new in WCAG 2.2, governs focus indicator appearance.

APCA Bronze Simple body-text lookup

Minimum Lc by font size and weight, taken from the W3C APCA Readability Criterion Bronze Simple Mode table. Apply the absolute value of Lc when checking against the threshold; the sign encodes polarity only.

Font sizeWeight 400 (regular)Weight 500 (medium)Weight 700 (bold)
14pxn/an/aLc 90
16pxLc 75Lc 70Lc 60
18pxLc 70Lc 65Lc 55
24pxLc 55Lc 50Lc 40
32pxn/an/aLc 30

Non-body-text APCA thresholds:

UseLc minimum
Non-text UI (focus indicators, button outlines, icon strokes)45
Spot reading (copyright footer, fine print)30
Decorative (logo marks, divider rules)No floor

Bronze Lc 60 at 16px is acceptable only at weight 700. The body-copy floor at weight 400 is Lc 75, which is why mid-grays on white that pass WCAG 2.x AA often fail APCA.

Where the two algorithms disagree

Test vectors with paired verdicts. All cells paired with the listed background. APCA column references Lc 75 (16px regular) as the body floor.

ForegroundBackgroundWCAG ratioWCAG AA normalAPCA LcAPCA 16px regular
#767676#FFFFFF4.54:1Pass53Fail
#595959#FFFFFF7.00:1Pass73Borderline
#4D4D4D#FFFFFF8.59:1Pass81Pass
#949494#FFFFFF3.04:1Fail40Fail
#6BA8E8#FFFFFF2.48:1Fail47Fail
#1F5EAE#FFFFFF4.51:1Pass71Borderline
#000000#FFEE0018.0:1Pass97Pass
#000000#00C89611.7:1Pass81Pass
#FFFFFF#4A4A4A8.50:1Pass−78Passreversed
#FFFFFF#6A6A6A4.83:1Pass−60Failreversed

The shape of the disagreement: WCAG is more forgiving on mid-gray text in the 4.5 to 6.0 ratio band. APCA is more forgiving on saturated yellows and greens because its luminance weighting is closer to ITU-R BT.709 than to the WCAG 2.x weights. Reverse polarity is where APCA gets strictest, since thin strokes lose effective contrast against dark backgrounds and the algorithm penalizes that explicitly.

Decision matrix: which standard applies

Pick the row that matches your project. The “Binding” column is what an auditor or regulator reaches for. The “Run alongside” column is what to add for your own quality bar.

Project typeBindingRun alongside
EU public sector or in-scope private (EAA, Jun 2025)WCAG 2.2 AA via EN 301 549APCA on mid-gray body text
US federal site or federal vendor (Section 508)WCAG 2.0 AAWCAG 2.2 AA on new builds
US state and local government (ADA Title II, Apr 2024 rule)WCAG 2.1 AAWCAG 2.2 AA on new builds
US private web product, no regulated industryNo legal floor; WCAG 2.x AA is industry defaultAPCA in design tokens
Internal design system, no statutory exposureYour choiceBoth metrics for token validation
iOS or Android app shipping to platform storeWCAG 2.1 AA (HIG and Material reference)Platform-specific guidance
WCAG 3.0 forward-looking researchAPCA BronzeWCAG 2.2 as floor

EAA enforcement allows fines up to €3M per violation in some member states. Section 508 violations affect federal procurement eligibility rather than producing direct fines. ADA Title II compliance dates: large public entities by April 2026, smaller entities by April 2027.

Under the hood: how the math works

WCAG 2.x contrast ratio uses CIE relative luminance with a piecewise sRGB gamma decode.

For each sRGB channel value c normalized to [0, 1]:

c_linear = c / 12.92                       if c <= 0.03928
c_linear = ((c + 0.055) / 1.055) ^ 2.4     otherwise

Relative luminance:

L = 0.2126 * R_linear + 0.7152 * G_linear + 0.0722 * B_linear

Contrast ratio:

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

The 0.05 offset is a flare term modeling display surface reflection. Polarity blindness comes from sorting by brightness before dividing.

APCA Lc generation applies a soft clamp on near-black values, uses a luminance weighting closer to ITU-R BT.709 (0.2126, 0.7152, 0.0722 with different gamma), raises L to a power (0.56 for text, 0.57 for non-text), takes the signed difference between text and background, and scales by 1.14 to land in a 0-to-100-ish range. The signed difference preserves polarity. The published reference implementation is apca-w3 on npm.

sRGB gamma decode lookup

Quick mental math for which channel dominates luminance. Linear values are after gamma decode; contribution at full G is the linear value times 0.7152.

sRGB byte (0–255)Linear valueContribution at full G
00.000000.000
320.010300.007
640.051260.037
960.127440.091
1280.215860.154
1600.318550.228
1920.456410.327
2240.650170.465
2551.000000.715

Saturated green at byte 192 contributes 0.327 to luminance. Saturated red at the same byte contributes 0.097. Saturated blue contributes 0.033. This is why bright yellows and greens lift WCAG ratios sharply and saturated blues barely move them.

Standards landscape

StandardYearBound byStatus
WCAG 2.02008Section 508 (2018 refresh)Stable, superseded for new audits
WCAG 2.12018EN 301 549 v3.2, ADA Title II Apr 2024Currently binding in EU and US state/local
WCAG 2.2Oct 2023EN 301 549 next updateCurrent Recommendation; adds SC 2.4.11
WCAG 3.0 working draftIn progressNoneEditor’s Draft only; expected post-2027
APCA Readability CriterionCandidate in WCAG 3NoneDraft; version pinned by apca-w3
EN 301 549 v3.2.12021EU procurement, EAA referenceCurrent EU baseline
ISO/IEC 405002012International mirror of WCAG 2.0Superseded
Section 508 (Revised)2018US federal procurementCurrent

Common pitfalls

SymptomCauseFix
Same pair gives different ratios in two toolsGamma decode precision; channel roundingDifferences under 0.05 are noise; ignore
AAA badge on a heading, normal-text badge fails on subtitle below itSubtitle is normal text, not large textCheck at 16px regular for the subtitle, not at heading size
Pair passes WCAG on swatch, looks unreadable in productionSubpixel rendering on thin weights at small sizesBump weight from 400 to 500 before re-checking
Tooltip at 70% opacity reports very high WCAG ratioMeasuring raw foreground, not composited foregroundComposite against the actual background first, then measure
Dark-mode pair at 4.6:1 passes AA but feels harder to readReverse polarity penalty; APCA flags thisTarget Lc 75 absolute for body in dark mode
Focus indicator at 1px and 2.8:1 fails auditSC 2.4.11 requires 2 CSS px thickness and 3:1 contrastIncrease ring to 2px and check contrast against adjacent background, not just the button

Related concepts

  • Relative luminance vs perceived lightness: WCAG uses Y from CIE XYZ. APCA uses a perceptual L closer to CIELAB L*. The two diverge most for mid-grays.
  • OKLCH color space: Perceptually uniform space useful when adjusting lightness without shifting hue. Recommended for auto-fix routines that need to preserve brand identity through a lightness adjustment.
  • EAA scope: Covers e-commerce, banking, transport ticketing, audiovisual media services, e-readers. Excludes micro-enterprises (under 10 employees and €2M turnover) in most member-state implementations.
  • Images of text: SC 1.4.5 limits images of text; an image with valid alt text shifts the contrast obligation to the alt text channel, not the rendered pixels.
  • WCAG 3.0 timeline: Editor’s Draft as of 2026; W3C Recommendation track typically takes 18 to 24 months past Candidate Recommendation. Production binding before 2028 is unlikely.
Read more on /learn