Dark Mode Contrast: What Actually Passes on Dark Backgrounds

Switching a theme to dark does not make it accessible — it just moves the failures somewhere new. White headlines will pass with room to spare, but the muted grays and brand colors you tuned for white backgrounds behave completely differently on dark ones. Every number below is computed with the WCAG 2.1 formula against real dark surfaces, so you can copy the exact hex values.

The polarity flip: your light-theme grays reverse their verdicts

The WCAG formula is symmetric — it only compares two luminances — so flipping a pair from dark-on-light to light-on-dark changes the ratio. Two familiar grays tell the whole story:

GrayOn whiteOn #121212Lesson
#9CA3AF2.54:1 fail7.38:1 AAAA failing light-theme gray becomes an excellent dark-theme secondary.
#6B72804.83:1 AA3.88:1 failA passing light-theme gray fails in dark mode. Never copy a gray across themes unchecked.

Rule of thumb: in dark mode, secondary text must be lighter than you expect. If your light theme's muted gray is around #6B7280, its dark-theme equivalent is closer to #9CA3AF or lighter.

Body and secondary text on #121212

#121212 is the standard near-black dark background (pure black is harsher and, on OLED screens, can smear during scrolling — near-black avoids both problems while still scoring AAA with white). Measured against it:

Text on #121212RatioVerdict (normal text)
#FFFFFF (primary)18.73:1AAA pass
#E5E7EB (soft primary)15.13:1AAA pass
#9CA3AF (secondary)7.38:1AAA pass
#6B7280 (muted)3.88:1Fail (large text only)
#52525B (disabled look)2.42:1Fail (even large text)
#E5E7EB on #121212 — 15.13:1, AAA.
#9CA3AF on #121212 — 7.38:1, AAA secondary text.
#6B7280 on #121212 — 3.88:1, fails normal text.

Note the disabled-text trap: #52525B at 2.42:1 fails even the 3:1 large-text bar. If disabled text still needs to be readable (a disabled button label, a caption), it is not exempt from contrast just because it is disabled — keep it at 3:1 or above, or remove it from the reading flow.

Cards are lighter than the background — re-check everything on them

Dark themes lift cards above the background (elevation). A card at #1E1E1E on a #121212 page is lighter, so every text color on it scores slightly lower:

TextOn #121212On card #1E1E1EStill passing?
#FFFFFF18.73:116.67:1Yes, AAA
#9CA3AF7.38:16.57:1Yes, AA (not AAA)
#6B72803.88:13.45:1No — large text only, either way

The drop is small but it demotes #9CA3AF from AAA to AA on cards. If your design system promises AAA secondary text, use a lighter secondary (such as #D1D5DB, 11.31:1 on #1E1E1E) on elevated surfaces. And the same rule applies to other dark surfaces: on slate #0F172A, #9CA3AF scores 7.03:1 and #6B7280 scores 3.69:1 — the same pass/fail pattern, slightly different numbers. Always measure against the actual surface, not the page background.

Accent colors: bright brand colors love dark backgrounds

Here dark mode is generous. Bright accents that are unreadable on white become excellent text colors on dark:

Accent on #121212RatioSame accent on white
#60A5FA blue7.37:1 AAA2.54:1 fail
#38BDF8 sky8.74:1 AAA2.14:1 fail
#A78BFA violet6.88:1 AA2.72:1 fail
#F472B6 pink7.07:1 AAA2.65:1 fail
#FBBF24 amber11.22:1 AAA1.67:1 fail
#34D399 emerald9.74:1 AAA1.92:1 fail

So in dark mode you usually do not darken the brand color for text — use the bright version as-is. The dark-mode mistake is the mirror image of the light-mode one: darkening an accent "to be safe" can push it back toward failure. If you need a link color, test the bright accent first; it probably already passes. One caution: a passing ratio is not the whole story — run bright-on-dark pairs through the color blindness simulator, since hue-only distinctions (green success vs red error) still fail users who cannot tell the hues apart.

The opacity trap: measure the blended color, not the percentage

Many design systems define dark-mode text as white at an opacity — 87% for primary, 60% for secondary, 38% for disabled. That is fine only if you check what the blend actually produces on each surface:

White opacity over #121212Blended solidRatioVerdict
87%#E0E0E014.19:1AAA pass
60%#A0A0A07.16:1AAA pass
38%#6C6C6C3.57:1Fail (large text only)

The 38% "disabled" level fails normal text — same trap as #52525B above. Worse, opacity blends depend on what is underneath: the same 60% white scores 7.16:1 over #121212 but 6.77:1 over a #1E1E1E card (blended #A5A5A5), and 38% white gives 3.57:1 on both — failing on both. Prefer solid grays from a fixed scale so a token means the same ratio everywhere it is used.

Dark mode checklist before you ship

Verify your dark theme in 10 seconds

Enter your background and text colors — the free checker computes the exact WCAG ratio and grades it against AA and AAA, in either polarity.

Open the Contrast Checker

FAQ

Is dark mode automatically accessible?

No. White headlines pass easily, but secondary text often fails: gray #6B7280 on #121212 scores 3.88:1, below the 4.5:1 AA bar for normal text, and #52525B scores only 2.42:1. Dark mode still needs measuring.

What gray should I use for secondary text on a dark background?

Use #9CA3AF or lighter. On #121212, #9CA3AF scores 7.38:1 (AAA) and #E5E7EB scores 15.13:1, while #6B7280 at 3.88:1 fails normal text. Do not carry a light-theme muted gray into dark mode without re-checking it.

Do brand colors need darkening for dark mode?

Usually the opposite: bright accents that fail on white pass easily on dark. Blue #60A5FA scores 2.54:1 on white (fail) but 7.37:1 on #121212 (AAA). In dark mode you can often use the bright brand color as-is for text.

Can I mute dark-mode text with opacity instead of a solid gray?

You can, but measure the result, not the opacity. White at 60% opacity over #121212 blends to solid #A0A0A0 and scores 7.16:1 (AAA), while white at 38% blends to #6C6C6C and scores only 3.57:1 (fail). Prefer a solid gray so the ratio is the same on every surface.

Are the WCAG thresholds the same in dark mode?

Yes — 4.5:1 for normal text at AA, 3:1 for large text, 7:1 for normal text at AAA. The formula is symmetric: it only cares about the two luminances, not which one is darker. A pair that passes in one polarity must be re-measured in the other.