Herramientas · Color · Comprobar el contraste de colores · Guías · Dark Mode Text Contrast: Why Light Gray Often Fails WCAG

Dark Mode Text Contrast: Why Light Gray Often Fails WCAG

5 min de lectura

Dark mode has a specific contrast trap that light mode mostly doesn't: text colors that look correctly muted on a dark surface are very often too close to the background to pass WCAG at all. It's an easy mistake to make, because the instinct that produces it - "pure white feels too harsh on black, so soften it" - is a reasonable design instinct that happens to point in exactly the wrong direction for contrast math.

Softened gray text on dark backgrounds often fails, even when it looks fine Two dark panels with light gray text. The left panel uses a commonly chosen medium gray that fails WCAG AA, labeled "about 3.9:1, fails 4.5:1". The right panel uses a lighter gray that passes, labeled "about 12:1, passes AA and AAA". Muted, "soft" gray about 3.9:1 - fails 4.5:1 Lighter gray about 12:1 - passes AA and AAA
Both grays read as "muted" against black. Only one of them is actually legible by the numbers.

Why dark mode makes this mistake so easy

On a light background, most designers instinctively reach for near-black text, which sits comfortably above every WCAG threshold without anyone doing the math - pure or near-pure black on white is close to the maximum possible ratio, 21:1. Dark mode flips the situation, and the instinct that served well in light mode works against you: pure white on black also passes easily, but it can look stark or clinical, so it's common to soften it toward a mid-gray for a calmer feel. That softening is exactly where the ratio erodes, and it erodes faster than it looks like it should, because human perception of brightness on a dark background isn't the mirror image of perception on a light one.

Where the numbers actually land

A commonly reached-for muted gray - something in the neighborhood of #797979 on a near-black #1c1c1c background - lands around 3.9:1. That clears the 3:1 threshold for large text but fails the 4.5:1 minimum for normal text at AA, the level most real interfaces need to hit. It's close enough to the line that it's genuinely easy to eyeball as "probably fine" and be wrong. A lighter gray in the same family, closer to #d8d8d8, lands around 12:1 and comfortably clears both AA and AAA on the same dark background - same intent, same restrained feel, real difference in the number.

The gap between "looks muted enough" and "is legible enough" is narrower on dark backgrounds than it is on light ones, which is exactly why guessing costs more here than it does in light mode.

Not sure where your own gray actually lands? Check it directly with the contrast checker - pick your background and text color and the ratio updates immediately.

Secondary text is where this bites hardest

Body copy tends to get checked, because it's the most obviously important text on the page. Secondary text - timestamps, captions, placeholder copy, disabled-state labels - gets muted more aggressively by design convention, precisely because it's meant to recede visually. That's a reasonable design goal, but "recede visually" and "fail WCAG" aren't the same requirement, and it's easy to conflate them. A timestamp that's supposed to read as quieter than the main content still needs to clear 4.5:1 if it's normal-size text someone is expected to actually read, not just glance past.

A site with both a light and a dark mode needs two separate checks

A text color chosen and verified for light mode tells you nothing about how the same role performs once the background flips to dark - they're two entirely different pairings, and passing one is no evidence about the other. A brand accent color used as a link color, for instance, might sit comfortably above 4.5:1 on white and drop well below it once the background becomes near-black, because the accent's own lightness didn't change but the thing it's now measured against did. Every text role that appears in both themes - body copy, links, secondary text, button labels - needs its own pass in each theme, not one check assumed to cover both.

A workable approach for a dark palette

Pick your near-black background first, since that's usually fixed by the rest of the design system. Then test candidate text grays against it directly, starting lighter than instinct suggests and only pulling it darker if the badges still pass comfortably - it's much easier to notice a color is "too bright" by eye than it is to notice it's "3.9 instead of 4.5" by eye. For anything explicitly secondary or de-emphasized, aim for the large-text threshold (3:1) only if it's genuinely rendered at large-text size (18pt/24px or larger, or 14pt/19px bold); otherwise it still needs the full 4.5:1 normal-text minimum, regardless of how quiet it's meant to feel.

Once a gray passes for one surface, reuse the same hex value everywhere that role appears rather than re-eyeballing a slightly different shade each time - consistency across a dark UI is easier to maintain when there's one checked value per text role instead of a dozen close variants, each one unverified.

Checking against more than one dark surface

A real dark-mode UI rarely has just one background - a page background, a raised card, a subtle hover state, each a slightly different near-black. A text gray checked once against the page background can still fail against a card that sits a shade lighter, since the ratio depends on both colors, not just the text. Where a design uses more than one dark surface tone, each one is worth its own quick check rather than assuming a pass against the darkest background covers every lighter surface the same text might sit on.

Probar Comprobar el contraste de colores gratis Comprobar el contraste de colores