Accessible Dark Backgrounds: Contrast, Legibility, and WCAG Compliance
Dark backgrounds look modern and they reduce screen glare in low-light conditions, but they make accessibility harder to get right, not easier. Light text on a dark surface fails for different reasons than dark text on a light one — pure white on pure black scores a perfect 21:1 on a contrast checker but can look harsh or blurry to some readers, while a muted grey that looks comfortable can drift under the threshold. This page is a practical guide to getting both the math and the perceived legibility right on the kinds of backgrounds covered elsewhere on this site: solid black, dark gradients, glassmorphism over photography, and saturated dark color combinations.
The Two Numbers That Matter
WCAG 2.1 sets contrast minimums based on luminance ratios between text and its background. The two thresholds you actually need to remember:
- 4.5:1 for normal text (under about 18pt, or under 14pt bold).
- 3:1 for large text and for non-text UI elements (icons, focus rings, form-control borders).
WCAG AAA tightens the small-text minimum to 7:1, which is worth aiming for on long-form reading surfaces but is not the working standard most sites are evaluated against.
The trap on dark surfaces is that the WCAG 2 ratio is symmetric but perception is not. The same ratio can look different with light text on dark than with dark text on light, and bright text on a dark field tends to glow slightly. That can push designers toward either fully white text or very low-contrast grey — both of which cause the problems described below.
Is a Dark or Light Background More Accessible?
Neither is more accessible for everyone; it depends on the reader and the setting.
- Dark text on a light background (positive polarity) is the long-standing default for reading, and several reading studies have found people read and proofread slightly better with it in normally lit rooms, because a bright page makes the pupil smaller and the image sharper.
- Light text on a dark background can cause halation: bright letters appear to bleed or blur into the dark surround. This is especially noticeable for people with astigmatism, and on long passages of small text.
- Some people need dark mode. Readers with light sensitivity (photophobia), migraines, or some low-vision conditions often find a bright page painful or washed out, and many people prefer dark interfaces at night.
The accessible answer is to support both and let the user choose: follow the operating-system setting with prefers-color-scheme, offer a manual toggle, and make sure both themes pass contrast on their own.
:root {
color-scheme: light dark;
--bg: #ffffff;
--text: #1a1a1a; /* 17.4:1 on #fff */
}
@media (prefers-color-scheme: dark) {
:root {
--bg: #121212;
--text: #e0e0e0; /* 14.19:1 on #121212 */
}
}
body {
background: var(--bg);
color: var(--text);
}
A manual toggle can set a data-theme attribute on <html> that overrides the media query, so readers who get halation in dark mode (or glare in light mode) can switch regardless of their system setting.
Quick Reference: Common Dark Background Pairings
| Background | Text color | Ratio | Body text (4.5:1) | Large/UI (3:1) |
|---|---|---|---|---|
| #000 | #ffffff | 21.0 | Pass | Pass |
| #000 | #e0e0e0 | 15.91 | Pass | Pass |
| #000 | #999999 | 7.37 | Pass | Pass |
| #0a0a0a | #777777 | 4.42 | Fail | Pass |
| #0a1a3a navy | #1a73e8 cobalt | 3.82 | Fail | Pass |
| #000 | #ff0000 | 5.25 | Pass | Pass |
| #000 | #00ff00 | 15.3 | Pass | Pass |
| #000 | #0000ff | 2.44 | Fail | Fail |
Two patterns jump out. Pure red on pure black (5.25:1) clears the 4.5:1 line for body text but not AAA; pure blue (2.44:1) is well below it, and cobalt on navy only works for large text and UI. Mid-grey body copy needs headroom — #777777 fails at 4.42:1 even on a near-black #0a0a0a, while #999999 passes comfortably at 7.37:1 on black.
Off-White Beats Pure White for Body Copy
Contrast checkers reward #fff on #000 with a perfect 21:1, but the highest score is not always the most readable. For some readers, especially those with astigmatism, fully bright white text on a fully black surface produces halation — the white appears to bleed into the surrounding black. The effect is more noticeable with small text and long passages.
The fix is to drop white slightly, and optionally lift the background off pure black. #e8e8e8 (17.14:1), #ddd (15.46:1), or a warm off-white like #f0e9d6 (17.33:1) all keep far more than 4.5:1 contrast against #000 while reducing the glare. Reserve pure white for headings, where the small text-area lets the harshness register as crispness rather than noise.
:root {
--bg: #050505;
--text-primary: #e8e8e8; /* body */
--text-secondary: #a0a0a0; /* metadata, labels */
--text-heading: #ffffff; /* H1/H2 only */
--link: #7eb6ff; /* light-blue link reads at 9.73:1 on #050505 */
--focus: #ffd76a; /* warm focus ring, 14.73:1, also visible to colorblind users */
}
Links and Focus States
Default browser blue (#0000ee) on a near-black background fails contrast badly. Lighten the link color until it sits comfortably above 4.5:1 on the page's actual background — for most dark themes, something in the #7eb6ff to #9ec6ff range works. Underline links on dark backgrounds too; if colour is the only thing that distinguishes a link from surrounding text, readers with colour vision deficiencies may not be able to tell what's clickable.
Focus rings get their own minimum: 3:1 against both the focused element and the surrounding background. A pure white ring on a dark surface satisfies that easily, but a brand-colored ring often does not. Default to a warm yellow or amber focus color; it visually distinguishes itself from typical brand palettes (which lean blue and purple) and reads clearly for users with red-green colorblindness.
Saturated Color on Dark Backgrounds
The colored-combo pages on this site (red and black, blue and black, green and black, purple and black) all share the same accessibility issue: saturated colors that feel "iconic" against pure black are usually below WCAG AA for body text. Use the saturated version only for short accents — buttons, badges, headings — and use a desaturated, lighter cousin for paragraphs.
Worked example for a "blue and black" interface:
- Page background:
#000or#0a0a0a. - Body text:
#dcdde0(off-white with a cool tint), not a blue. - Buttons / accent:
#1a73e8as the button fill (4.66:1 against#000, 4.39:1 against#0a0a0a— fine for a UI component, which needs 3:1). White button text on it is 4.51:1, just passing AA. - Inline links:
#86b8ff(10.31:1 on#000, 9.72:1 on#0a0a0a— passes for body text). - Disabled state:
#5a6072at 50% opacity, with the disabled affordance reinforced by a label, not just by being dimmer.
Glassmorphism and Photo Overlays
Glass surfaces and photo-backed heroes are the hardest cases for contrast. The "background" the text sits on is not a single color — it's whatever happens to be behind the blur or photo at that pixel. Two practical rules:
- Always darken under text. Sandwich a translucent dark gradient (
rgba(0,0,0,0.55)torgba(0,0,0,0.85)) between the photo and the copy. This is the trick that background blend modes are good for; it stabilizes contrast across all the underlying images you might swap in. - Test against the worst frame. If the hero cycles photos, check contrast against the brightest one, not a representative one. The page is only as accessible as its weakest state.
Tools That Belong in Your Workflow
- The WebAIM Contrast Checker for spot-checks.
- Browser DevTools — both Chrome and Firefox surface contrast directly in the element inspector, including the WCAG AA / AAA verdict.
- The
contrast-color()CSS function (drafted earlier ascolor-contrast()), which picks black or white text for a given background. Browser support is still limited, so treat it as progressive enhancement with a static fallback. - A colorblind simulator — DevTools also includes deuteranopia, protanopia, and tritanopia rendering modes. Every dark palette should be checked under at least deuteranopia, since red-green colour vision deficiency is the most common type.
Accessibility Checklist for Dark Backgrounds
- Body text ≥ 4.5:1 against the actual surface, not a darker reference.
- Body text not pure white; halation handled.
- Link color clearly distinguishable from body text and meets 4.5:1.
- Underline or icon on links — color alone never carries meaning.
- Focus ring at 3:1 against both the focused element and its surroundings.
- Button text ≥ 4.5:1 against the button surface; if the button is a saturated brand color, check first.
- Photo/glass backgrounds shipped with a darkening overlay; contrast checked against the brightest underlying frame.
- Page rendered with deuteranopia simulation — visual hierarchy still readable.
color-scheme: darkdeclared on the root so form controls render in dark mode.- Animation respects
prefers-reduced-motion; the static fallback also passes contrast.
For the broader coverage of dark CSS surfaces this checklist applies to, see dark backgrounds, the background-color reference, and dark-mode backgrounds with prefers-color-scheme. For specific palettes, the colored-combo pages each include accessibility notes that build on what's here. To test your own colour pair, use the dark background contrast checker; for off-black base colours and their ratios with white text, see shades of black in CSS.