Dark mode accessibility: contrast, colors and user choice
WCAG does not require a dark mode, but a dark theme you ship has to meet the same contrast ratios as the light one: 4.5:1 for text (3:1 for large text) and 3:1 for the parts of controls and graphics people need to see. Dark is not automatically easier to read, because some people need a dark background and others read better on a light one. Follow the visitor's system setting, let them override it, and test each theme on its own.
Published . Last reviewed .
A dark theme shows light text on a dark background. People turn it on in an operating system or browser setting, and a site can follow that choice with the prefers-color-scheme media feature, which MDN describes as detecting whether a user has requested a light or dark theme. W3C's Understanding pages for 1.4.3 Contrast (Minimum) and 1.4.11 Non-text Contrast never use the phrase "dark mode", and neither criterion asks for a dark theme. They measure the colors your styles put on screen, and a dark theme is a second set of colors, which is why a site that passes in light mode can fail in dark mode.
For the ratios, see our color contrast guide and our pages on 1.4.3 and 1.4.11.
Is dark mode more accessible than light mode?
Neither suits everyone. W3C's low vision working draft (a 2016 First Public Working Draft, not a standard) says some people with light sensitivity find a light background painful and need a darker one, while others read better with dark text on a light background. It adds that the combination that works differs widely between people and can vary for the same reader with fatigue and lighting.
WCAG leaves room for this. The 1.4.3 Understanding page says some people with cognitive disabilities need low-contrast combinations, so authors are encouraged to provide ways to adjust colors. 1.4.8 Visual Presentation (Level AAA; see conformance levels) asks that, for blocks of text, users can select foreground and background colors, and W3C says the browser can provide that.
So dark mode is a choice to offer, not a fix to apply: follow the visitor's own setting, and let them override it.
What WCAG requires of a dark theme
WCAG's definition of contrast ratio says conformance is evaluated for color pairs the content specifies and an author would expect to appear adjacent. Authors need not consider color changes made by the user agent, "except where caused by authors' code" (note 6, repeated in the Key Terms of the 1.4.3 page). A dark theme your stylesheet applies to visitors whose system is set to dark is caused by your code, so in our reading each theme is its own set of pairs to test. W3C lists G174, a control that switches to a sufficient-contrast presentation, as another route, but we would not rely on it for a theme that applies automatically.
| Part of the page | Criterion | Minimum | A usual slip |
|---|---|---|---|
| Body text, labels, links, headings | 1.4.3 (AA) | 4.5:1 | Muted gray text on dark surfaces |
| Large text (18pt, or 14pt bold: about 24px and 18.5px) | 1.4.3 (AA) | 3:1 | A brand color reused unchanged |
| Placeholder text, and text shown on hover or focus | 1.4.3 (AA) | The ratio for its size | Faint gray placeholders (see placeholder text) |
| Input borders, icons, focus indicators, chart lines | 1.4.11 (AA) | 3:1 against adjacent colors | Dark gray borders on a dark surface |
| Disabled controls, text in a logo | Exempt | None | Dimming a control that is still operable |
Two rules from W3C's pages carry over unchanged:
- Light on dark is measured the same way. The ratio is (L1 + 0.05) / (L2 + 0.05), where L1 is the relative luminance of the lighter color and L2 of the darker; relative luminance is a color's brightness from 0 for black to 1 for white. Ratios run from 1:1 to 21:1 and are not rounded: 4.499:1 fails 4.5:1.
- Set text and background together. W3C lists F24 as a failure: specifying a foreground color without a background color, or the reverse, because the author can no longer guarantee the contrast the visitor ends up with. The contrast ratio definition adds that where no background color is specified, white is assumed, so light text set in a dark media query with no background would be measured against white.
Why one brand color rarely works in both themes
Contrast is a ratio between two luminances, so one color earns a different ratio on each background. On white, 4.5:1 needs a relative luminance of 0.183 or less. On #111111 it needs 0.200 or more, so no color reaches 4.5:1 on both. We computed the ratios below with the WCAG formula, the one our contrast checker uses, and cut them off at two decimals rather than rounding up.
| Color | On white (#FFFFFF) | On dark (#111111) | Against 4.5:1 |
|---|---|---|---|
| Blue #2F80ED | 3.86:1 | 4.88:1 | Fails on white, passes on dark |
| Darker blue #2274E0 | 4.52:1 | 4.17:1 | Passes on white, fails on dark |
| Yellow #FFC933 | 1.53:1 | 12.27:1 | Fails on white, passes on dark |
| Dark gold #947100 | 4.54:1 | 4.15:1 | Passes on white, fails on dark |
Give each color role two values: a darker step for the light theme and a lighter step of the same hue for the dark theme. Our accessible color palette tool works this way, measuring every pair against a light and a dark background you set and giving each color an on-light and an on-dark version. The 3:1 parts are more forgiving: blue #2F80ED at 3.86:1 on white is too weak for 16px body text but acceptable for a large heading, an icon or a border. See the large text exception and building an accessible brand palette.
The 1.4.3 page says effective luminance contrast can generally be computed without regard to specific color deficiency, with one exception that dark themes meet: long-wavelength colors such as red against darker colors can be a problem for people with protanopia, and W3C carries an advisory technique on avoiding red on black. Check a bright red link on a dark surface in the color blindness simulator, and see designing for color blindness.
Where dark themes usually break
The pairs below are our own examples, computed the same way.
| Pair | Ratio | Needs | Result |
|---|---|---|---|
| Muted text #6B6B6B on #121212 | 3.51:1 | 4.5:1 | Fails |
| Muted text #8C8C8C on #121212 | 5.57:1 | 4.5:1 | Passes |
| The same #8C8C8C on a raised card #2D2D2D | 4.09:1 | 4.5:1 | Fails |
| Input border #333333 on #121212 | 1.48:1 | 3:1 | Fails, where the border is what shows the field |
| Input border #767676 on #121212 | 4.12:1 | 3:1 | Passes |
- Muted text on raised surfaces. Dark themes often use lighter grays for cards, menus and dialogs, so text that passes on the page background can fail on the card above it (third row).
- Borders and dividers. W3C's 1.4.11 page says a control needs no visible boundary when its text or an icon identifies it, but where the boundary is what identifies it, it needs 3:1 against the adjacent color. A subtle border like the fourth row fails.
- Focus indicators. A focus indicator must contrast with adjacent colors. A browser's default indicator is exempt if left alone, and W3C's failure F78 covers styling outlines so the indicator disappears. A dark ring styled for the light theme can vanish on a dark surface; see focus indicators.
- Images, logos and icons. A dark logo or icon on a transparent background can disappear in a dark theme. A web.dev article on dark mode shows a
pictureelement whosesourceusesmedia="(prefers-color-scheme: dark)"to serve each theme its own image, and recommendscurrentColorso inline SVG icons inherit the text color. Charts need lines and slices that hold 3:1 in both themes (see SVG accessibility), and text over a photo has its own guide: text over images.
Pure white on pure black is 21:1, the top of the scale, and nothing in 1.4.3 forbids it. The web.dev article advises a slightly darker white such as rgb(250, 250, 250) to reduce glow. That is design advice, not a rule: choose softer pairs if they suit your audience, and check they still pass (#E6E6E6 on #121212 is 15.01:1).
Follow the visitor's setting in CSS
- Declare both schemes. The
color-schemeproperty, set tolight darkon:root, lets the browser adapt the canvas color, scrollbars and form controls. Themetatag of the same name, in theheadbefore any CSS, helps prevent a flash during load. Neither sets your own colors for you: they change browser defaults, and the text, background and border colors your design uses stay yours to specify. - Use custom properties and a dark media query. MDN's
prefers-color-schemepage describes a light default with a dark override as a common usage. Itslightvalue also matches visitors with no preference, and the feature has been widely available since January 2020. - Or use
light-dark(). This function returns its first value in a light scheme and its second in a dark one, oncecolor-schemeis set tolight dark. MDN marks it newly available since May 2024.
A minimal version, with the contrast of each pair on its page background computed in the comments:
<meta name="color-scheme" content="light dark">
:root {
color-scheme: light dark;
--bg: #ffffff;
--text: #1f2328; /* 15.79:1 */
--link: #2274e0; /* 4.52:1 */
--border: #767676; /* 4.54:1, needs 3:1 */
}
@media (prefers-color-scheme: dark) {
:root {
--bg: #121212;
--text: #e6e6e6; /* 15.01:1 */
--link: #8ab4f8; /* 8.88:1 */
--border: #767676; /* 4.12:1, needs 3:1 */
}
}
body { color: var(--text); background-color: var(--bg); }
Text and background are set together, as F24 requires.
Let visitors override it
The web.dev article calls it a great pattern to follow the system setting first and then optionally let users override it, so someone can keep their device in dark mode and view your site in light, or the reverse; its demo keeps the choice across reloads. MDN's page for light-dark() notes that forcing a scheme over the user's preference is generally discouraged. Our reading: follow the system until the visitor chooses, then remember it. Make the toggle a real button with a name that says what it does and a focus indicator that shows in both themes, and apply a remembered choice early, since a bright flash of the wrong theme is unwelcome for anyone sensitive to light.
High contrast and forced colors
Forced colors mode is a mode in which the browser enforces a user-chosen palette; MDN's forced-colors page gives Windows High Contrast as its example. When it is active, the browser ignores your text, background, border, outline and SVG fill and stroke colors and paints system colors, removes shadows and non-URL background images, and treats color-scheme as light dark. The colors your dark theme sets for those properties are not used, and MDN advises against building a separate design for this mode. Make small fixes instead: MDN's example is a button whose edge came from a box-shadow, which vanishes, so a real border is added inside a forced-colors: active query. Using forced-color-adjust: none turns the user's palette off for an element, so we would reserve it for narrow cases.
Check it yourself
Test each theme separately:
- Switch the theme. Change your system setting, or emulate the color scheme for a tab in your browser's developer tools (the web.dev article mentions this).
- Measure each text pair on the surface it sits on in the contrast checker, which gives the exact ratio, a pass or fail at AA and AAA, and the nearest color that passes. Include muted text, placeholders and text on cards.
- Build the pairs together in the accessible color palette tool, which shows every pair against a light and a dark background.
- Check what is not text: borders, icons, focus indicators, chart lines and the theme toggle, against 3:1.
- Check text over images by drawing a box around the text in the image contrast checker, which reports the contrast at its worst spot.
- Run the accessibility bookmarklet on the live page in dark mode. It measures the text actually on screen, and lists for a manual check any text on a page that sets no background color when the browser shows a dark color scheme.
- Repeat in forced colors: turn on your system's high contrast setting and tab through the page.
The free scan reads the HTML your server sends and has no CSS engine, so it cannot see the colors of either theme (see what we check). Scan my site for free for what markup can show, and use the routine above for color. On monitored pages, GotAlt's browser check loads each page once, signed out, and does not click a theme toggle or ask the browser for a dark color scheme, so the dark theme stays yours to test. The rest of a site test is in how to test website accessibility.
Keep it checked
A redesign, a new component or a changed brand color adds new color pairs after your last review. GotAlt checks the pages you monitor every week, compares each image's alt text with the image itself (up to six images per page), runs its rule checks, opens monitored pages in a browser for contrast and other render-dependent checks (see what we check), and reports what changed. Plans are from $69 a month. Audit my whole site from $69/mo.
Dark mode questions
Does WCAG require a dark mode?
No. W3C's Understanding pages for 1.4.3 and 1.4.11 do not mention dark mode, and no success criterion asks for a dark theme. If you ship one, its text and controls are still measured: 4.5:1 for normal text, 3:1 for large text and 3:1 for the parts of controls and graphics people need to see. Level AAA 1.4.8 asks that users can choose colors, which a browser can provide.
Is dark mode better for people with low vision?
Not for everyone. W3C's 2016 low vision working draft says some people with light sensitivity need a darker background, while others read better with dark text on a light background, and the best colors can vary for the same reader with fatigue and lighting. Follow the system setting and let visitors override it.
What contrast ratio does a dark theme need?
The same as a light one. Text needs 4.5:1, or 3:1 for large text (at least 18pt, or 14pt bold, about 24px and 18.5px). Controls and meaningful graphics need 3:1 against adjacent colors. The ratio compares the lighter color's luminance with the darker one's, so it does not matter which color is the text. Ratios are not rounded.
Is white text on a pure black background bad?
WCAG sets minimums, and pure white on black is 21:1, the top of the scale, so 1.4.3 does not forbid it. The web.dev dark mode article advises a slightly darker white to reduce glow, and W3C's low vision draft notes that some people need low text brightness. Choose softer pairs if you like, and check they still pass.
How do I detect a visitor's dark mode setting in CSS?
Use the prefers-color-scheme media feature. Its dark value means the user requested a dark theme, and light means they prefer light or have expressed no preference. Set color-scheme: light dark so browsers adapt form controls and scrollbars, and override your color custom properties inside a (prefers-color-scheme: dark) query.
Should I add a dark mode toggle to my site?
Follow the system setting by default, and add a toggle if visitors may want a different theme on your site than on their device. The web.dev dark mode article calls following the system first and then optionally allowing an override a great pattern. We would remember the choice, make the toggle a real button with a clear name and a focus indicator that shows in both themes, and not force a theme on anyone.
What happens to my dark theme in Windows High Contrast mode?
In forced colors mode the browser replaces your text, background, border, outline and SVG colors with the user's palette, and removes shadows and non-URL background images, as MDN's forced-colors page explains. The colors your dark theme sets for those properties are not used. Fix only what breaks, such as a button whose edge was a shadow, by adding a real border.
Start with what the markup can show
The free scan reads your pages' HTML and reports rule-based WCAG findings. It cannot judge the colors of either theme. No signup.
Scan my site for freeRelated guides
- Color contrast: the WCAG ratios and how to test them.
- An accessible brand palette: how to choose colors that pass.
- Designing for color blindness: what to change beyond contrast.
- The large text exception: when 3:1 is enough.
- Links and use of color: underlines, contrast and WCAG 1.4.1.
- Placeholder text: its contrast, and why it is not a label.
- Focus indicators: visible, high contrast and never hidden.