AppCrib
Design Tools

Why WCAG 2.2 and APCA Disagree About Dark Mode Text

Domain knowledge·Published by AppCrib··
RatiaContrast ratio, instantly clear.

A designer building a dark dashboard picks #FFFFFF text on a #1A1A2E navy background. WCAG returns 15.83:1, comfortably above the 4.5:1 floor for body text. APCA returns approximately Lc +93. Both standards say the pair passes.

Then she tests the inverse out of curiosity, swapping to #1A1A2E text on a #FFFFFF background. WCAG returns the same number, 15.83:1, because the formula doesn't care which color is the foreground. APCA returns roughly Lc -101. The magnitudes differ. The eye sees the two pairs differently. WCAG can't.

This is the polarity problem in accessibility contrast, and it's why teams shipping serious dark mode work keep two numbers on screen at once.

The 4.5:1 floor was published in December 2008

WCAG 2.0 became a W3C Recommendation in December 2008. Section 1.4.3 of that document defines the contrast ratio every modern checker still computes:

ratio = (L1 + 0.05) / (L2 + 0.05)

L1 and L2 are the relative luminance values of the two colors, with L1 always the lighter of the two. The 0.05 is a flare correction, an idealized ambient-light reflection that keeps the ratio finite at the bottom of the scale. The 4.5:1 threshold for body text traces back to vision research from the 1990s. Aries Arditi at Lighthouse International, along with collaborators studying low-vision typography, established that around 4.5:1 of luminance ratio is roughly the contrast a reader with 20/80 acuity needs to read 12-point text comfortably. The W3C cited that work directly in the WCAG 2.0 understanding documents.

The formula was designed to be deterministic, computable on any client, and symmetric. Whichever color is darker, the ratio is the same. In 2008, that symmetry was sensible. CRT monitors were still on desks. iOS dark mode wouldn't ship until 2019. Almost all UI text was dark on light, and treating the foreground-background pair as unordered didn't cost anything because designers weren't routinely producing both polarities of the same theme.

The cost showed up later, when dark mode went from a power-user toggle to a system default and palettes started shipping in mirrored pairs.

APCA is asymmetric on purpose

APCA, the Advanced Perceptual Contrast Algorithm, was developed beginning in 2019 by Andrew Somers as part of the WCAG 3 contrast work. Its design brief is the opposite of symmetric. APCA computes a signed Lc value: positive when the text is lighter than the background, negative when the text is darker. The magnitude represents perceived contrast, calibrated against typography legibility studies rather than against luminance alone.

The two algorithms diverge in three structural ways.

The first is polarity. WCAG's ratio is direction-blind. APCA tracks which color is doing the writing. The same luminance gap produces a different Lc depending on whether you're reading dark glyphs on a light field or light glyphs on a dark field. The human visual system has different sensitivity in each case, and APCA reports that difference.

The second is the lightness curve. WCAG uses relative luminance straight from the sRGB definition. APCA applies a perceptual lightness function, a power curve similar in spirit to CIE L* but tuned for screen typography. That curve compresses the high end and expands the mid-tones, which is where most real legibility problems live.

The third is the threshold model. WCAG gives one ratio and one decision boundary per text size. APCA gives you Lc and a font-size lookup table. The same Lc 60 score might be "pass" for 24px headline text and "caution" for 14px body. The legibility floor moves with the type, the weight, and even the typeface category. APCA explicitly distinguishes thin glyphs from heavy ones in a way WCAG never has.

A handful of pairs where the disagreement is loudest

ForegroundBackgroundWCAG ratioAPCA Lc (approx)AA normalAPCA body verdict
#000000#FFFFFF21.00:1-108PassPass
#FFFFFF#00000021.00:1+106PassPass
#555555#FFFFFF7.46:1-80PassPass
#FFFFFF#5555557.46:1+73PassBorderline
#888888#FFFFFF3.54:1-63FailCaution
#FFFFFF#8888883.54:1+55FailBelow body floor

Two patterns to notice. The black-on-white and white-on-black pairs report identical 21:1 WCAG ratios, but APCA magnitudes differ by about two points: the dark-on-light direction nets slightly more perceived contrast. And the borderline pairs in the middle of the table tell a more interesting story. WCAG flags them identically. APCA places the light-on-dark version noticeably lower than its inverse. A dark-mode body paragraph that reads as "barely caution" in APCA passes its WCAG inverse with the same number on the scorecard.

The further you walk into mid-tones, the wider the disagreement gets.

Where the disagreement actually matters

Mid-tone tints are the most common danger zone. Light gray text on warm cream, white text on a brand teal at 50% lightness, dark gray text on a muted navy. These are exactly the design moves that look fine in mockups, clear WCAG 4.5:1 by a hair, and fail APCA at body sizes. The pair "looks" lower contrast than the WCAG number suggests, because the eye is doing perceptual work the formula isn't modeling.

Dark mode is where the polarity asymmetry shows up most reliably. A theme that flips a light-mode palette to its inverse will produce identical WCAG numbers for every text element. It will read measurably differently. Body text especially. The asymmetry compounds at smaller type sizes because APCA's font-size weighting penalizes thin glyphs on dark fields more aggressively than thick glyphs on light fields. Teams who ship a dark theme by mirroring a light palette and then run only WCAG checks routinely deploy body copy that looks thinner and less legible than its light-mode counterpart, and they don't know it because the numbers match.

Display typography goes the other way. APCA is more forgiving of large bold text than WCAG. An Lc 60 paired with a 32px bold headline is acceptable under APCA's font lookup, while WCAG would fail the same pair at 4.5:1 for normal text and only warn at 3:1 for large text. If you're designing oversized hero typography over a tinted background, APCA gives you legitimate headroom WCAG doesn't. The cases where WCAG is more conservative than APCA are rarer than the reverse, but they're real, and they explain why APCA hasn't been universally cheered as "stricter" by the design community. It just disagrees in different places.

Why APCA is still a candidate, not the standard

WCAG 3 has been in working draft status at the W3C since January 2021. As of early 2026, it remains a working draft, with a target Recommendation date that's drifted from an early "2023" through "no earlier than 2025" and now sits at something closer to 2027. APCA is one of several candidate algorithms for the visual-contrast success criterion in WCAG 3, and it hasn't been formally adopted. The reference implementation, apca-w3 on npm, has shipped through several calibration revisions including version 0.0.98 and follow-on stability passes, and the spec authors have been explicit that Lc values can shift between releases.

While that work continues, the rest of the regulatory stack stays anchored on WCAG 2.x. The European Accessibility Act became enforceable on June 28, 2025, and it references WCAG 2.1 AA. The US Department of Justice's April 2024 final rule under ADA Title II also references WCAG 2.1 AA. Section 508 procurement in the US federal supply chain currently points at WCAG 2.0. None of these regulations have a path to APCA without an upstream WCAG 3 Recommendation first.

So compliance reports still need WCAG. Designer judgment about legibility is the part where APCA earns its place.

The practical pattern most teams settle on

A few rules that hold up across design teams and accessibility consultants who've worked with both standards.

WCAG ratios go into compliance documentation. The numbers are stable, the thresholds are referenced by current regulation, and an audit using WCAG 2.2 AA will line up with whatever the legal review is checking against. There's no shortcut around this for now.

APCA goes into design QA. When WCAG passes but APCA flags caution, the user is going to notice. Especially in dark mode. Especially at body sizes. Especially on tinted surfaces where mid-tone contrast does the heavy lifting.

Polarity gets tested both ways. If a palette ships with both a light and a dark theme, every text color belongs in both directions through an APCA check. WCAG will report them as equivalent. They aren't, and the dark-mode side is usually the one that suffers.

The APCA library version gets pinned to an exact release. Last month's Lc 75 isn't guaranteed to be this month's Lc 75 while the spec is still moving. Pin the version, document it next to the score in any QA artifact, and reverify whenever you upgrade.

Lc and ratio don't translate. Lc 60 isn't "equivalent to" 4.5:1, even if both numbers happen to flip the same pair from pass to fail in a few common cases. The two algorithms answer related but distinct questions about the same color pair, and trying to use one as a proxy for the other quietly hides the cases where they actually disagree.

A side-by-side view of both numbers, on the same screen, with polarity-swappable inputs, is the easiest way to keep both standards honest while the WCAG 3 work finishes. Ratia displays both verdicts for any color pair, flips polarity in a click, and the URL in the address bar already encodes whichever direction you're testing.

Ratia
Contrast ratio, instantly clear.
Try Ratia