
How does dark mode affect typography?
- Sajjad
- Typography
- 11 Oct, 2026
Dark mode typography behaves differently from light mode because light text on a dark background appears bolder, brighter and slightly larger than the same text in dark ink on white. Bright strokes seem to bleed into the surrounding dark area, an effect often called halation, which some readers, particularly people with astigmatism, find blurry or tiring. To compensate, you usually soften the text colour away from pure white, use a dark grey rather than pure black background, reduce font weight slightly, and sometimes add a touch more letter spacing and line height. Contrast still needs to meet WCAG, but extreme contrast isn't the goal.
Many people now browse with a dark system theme, and sites increasingly follow it automatically. Simply inverting your light palette rarely works well: text that looked crisp and balanced in light mode can look heavy and glaring in dark mode, and colours that passed contrast checks may not. In this article you'll learn why text looks different on dark backgrounds, how to choose text and background colours, how to adjust weight and spacing, how to handle accent colours, code and images, and how to implement and test it all in CSS.
Why Text Looks Different on Dark Backgrounds
On a light background, text is a dark shape surrounded by light. On a dark background, the letters themselves are the light source. The eye perceives bright areas as slightly larger than they physically are, a phenomenon known as irradiation, so light strokes on dark appear thicker and the gaps inside and between letters seem to shrink.
That has a few practical effects:
- Text looks bolder: A regular weight can look closer to medium, and bold text can look heavy.
- Thin details fill in: Small counters, such as those in e and a, may close up visually at small sizes.
- Glare increases: Very bright text on very dark backgrounds can appear to shimmer or glow, especially for readers with astigmatism.
- Long reading is harder for some people: Many readers find long passages more comfortable in light mode, while others prefer dark. That's why letting users choose is better than forcing either.
Choosing Text and Background Colours
Avoid Pure Black Backgrounds
A pure black background (#000000) maximises contrast and on OLED screens turns pixels off completely, but it makes halation worse and can cause smearing when scrolling on some OLED displays. A very dark grey is gentler and gives you room to show elevation with slightly lighter surfaces. Google's Material Design, for example, recommends #121212 as a dark theme base surface.
Avoid Pure White Text
Pure white text (#ffffff) on a near-black background is very intense. An off-white or light grey keeps contrast high while reducing glare:
:root {
color-scheme: light dark;
--bg: #ffffff;
--text: #1a1a1a;
--text-muted: #525252;
}
@media (prefers-color-scheme: dark) {
:root {
--bg: #121212;
--text: #e4e4e4; /* about 14.7:1 on #121212 */
--text-muted: #a3a3a3; /* about 7.4:1 on #121212 */
}
}
body {
background-color: var(--bg);
color: var(--text);
}
The color-scheme declaration tells the browser your page supports both schemes, so built-in elements such as form controls and scrollbars switch to match.
Keep Contrast Within a Comfortable Range
WCAG's contrast requirements apply in dark mode exactly as they do in light mode: at least 4.5:1 for normal text and 3:1 for large text at Level AA. The difference is that in dark mode it's easy to overshoot. A useful target for body text is somewhere between about 10:1 and 15:1, which is comfortably above AAA without the starkness of 21:1. For more on calculating ratios, see how much colour contrast text needs for WCAG.
Don't Use Transparent White for Hierarchy
Using white at reduced opacity for secondary text, such as rgba(255, 255, 255, 0.6), is common, but the resulting colour depends on what's behind it, and the effective contrast changes from one surface to the next. Solid colour tokens are easier to test and keep consistent.
Adjust Font Weight
Because light text looks heavier, many designers reduce the weight slightly in dark mode. With a variable font, you can make subtle adjustments rather than jumping a full weight step:
@font-face {
font-family: "Inter";
src: url("/fonts/Inter-Variable.woff2") format("woff2");
font-weight: 100 900;
font-display: swap;
}
body {
font-family: "Inter", system-ui, sans-serif;
font-weight: 400;
}
strong,
b {
font-weight: 700;
}
@media (prefers-color-scheme: dark) {
body {
font-weight: 370;
}
strong,
b {
font-weight: 650;
}
}
Keep the change modest. Going too light reintroduces thin strokes that are hard to read, especially at small sizes and on lower-resolution screens. With static fonts that only offer 400 and 700, it's usually better not to change body weight at all than to drop to 300.
Use a Grade Axis Where Available
Changing weight also changes the width of letters, which can make text reflow and lines break differently between themes. Some variable fonts include a grade axis (GRAD), which changes stroke thickness without changing letter widths. Roboto Flex and Google's Material Symbols are examples. Where a font has it, grade is the ideal tool for dark mode:
.uses-roboto-flex {
font-family: "Roboto Flex", system-ui, sans-serif;
}
@media (prefers-color-scheme: dark) {
.uses-roboto-flex {
font-variation-settings: "GRAD" -25;
}
}
Check the font's documentation for the supported range of the axis, because it varies between fonts.
Adjust Spacing and Size
Because letters appear to swell slightly on dark backgrounds, a small increase in spacing can restore their clarity:
- Letter spacing: A tiny positive value, such as 0.01em, helps small text.
- Line height: Adding a little, for example from 1.5 to 1.6, can make long passages feel less dense.
- Font size: Generally leave it alone. Changing size between themes changes layout and is rarely needed.
@media (prefers-color-scheme: dark) {
.prose {
letter-spacing: 0.01em;
line-height: 1.6;
}
}
These are small refinements. Judge them by eye on real screens rather than applying them by formula.
Colour Accents, Links and Code
Desaturate and Lighten Accent Colours
Saturated colours that look good on white often vibrate against dark backgrounds, and dark brand colours may fail contrast completely. Use lighter, slightly desaturated versions for links and highlighted text:
:root {
--link: #1d4ed8; /* 6.7:1 on white */
}
@media (prefers-color-scheme: dark) {
:root {
--link: #93b4fd; /* about 9.1:1 on #121212 */
}
}
a {
color: var(--link);
text-underline-offset: 0.18em;
}
Keep links underlined in both schemes, so they don't depend on colour alone.
Syntax Highlighting
Code blocks need their own dark palette. Many syntax themes designed for editors use very saturated colours and pure black backgrounds. Choose or adjust a theme so every token colour meets at least 4.5:1 against the code block background, and avoid using colour alone to convey meaning in code samples.
Text on Images and Shadows
Box shadows are almost invisible on dark backgrounds, so use slightly lighter surface colours to show elevation instead. For text on images, check contrast again in dark mode, because overlays tuned for a light page may not suit a dark one.
Implementing Dark Mode in CSS
There are two common patterns. The first follows the operating system using prefers-color-scheme, as in the examples above. The second also lets users choose, which is better because preferences for reading can differ from system settings.
A Toggle That Respects the System Default
This pattern uses a data-theme attribute on the root element when the user has made a choice, and falls back to the system setting otherwise:
:root {
color-scheme: light;
--bg: #ffffff;
--text: #1a1a1a;
--link: #1d4ed8;
}
@media (prefers-color-scheme: dark) {
:root:not([data-theme="light"]) {
color-scheme: dark;
--bg: #121212;
--text: #e4e4e4;
--link: #93b4fd;
}
}
:root[data-theme="dark"] {
color-scheme: dark;
--bg: #121212;
--text: #e4e4e4;
--link: #93b4fd;
}
const button = document.querySelector("#theme-toggle");
function currentTheme() {
const set = document.documentElement.dataset.theme;
if (set) return set;
return window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
}
button.addEventListener("click", () => {
const next = currentTheme() === "dark" ? "light" : "dark";
document.documentElement.dataset.theme = next;
try {
localStorage.setItem("theme", next);
} catch {
// Storage unavailable; the choice lasts for this page view.
}
});
To avoid a flash of the wrong theme, read the saved preference in a small inline script in the head before the page renders.
The light-dark() Function
Current browsers support the light-dark() CSS function, which picks one of two values based on the active color-scheme. It keeps paired values together:
:root {
color-scheme: light dark;
}
body {
background-color: light-dark(#ffffff, #121212);
color: light-dark(#1a1a1a, #e4e4e4);
}
light-dark() only works for colour values, so weight and spacing adjustments still need a media query or attribute selector.
How to Test Dark Mode Typography
- Switch your operating system theme: Or use developer tools. In Chrome, open the Rendering panel and set Emulate CSS media feature prefers-color-scheme to dark.
- Check every text colour pairing: Body, muted, link, visited, button, badge and code colours all need checking on each surface they appear on.
- Read a long article: Glare and heaviness show up over several minutes of reading, not in a quick glance.
- Test on different screens: OLED phones, LCD laptops and external monitors render dark themes quite differently.
- Test at low brightness: Many people use dark mode at night with the screen dimmed, where low-contrast muted text disappears first.
FAQ: Dark Mode Typography
It's usually better not to. Pure white on a very dark background can cause glare and a blurry glow for some readers. An off-white such as #e4e4e4 keeps contrast high while being more comfortable.
Often slightly, yes. Light text on dark looks bolder, so reducing the weight a little, for example from 400 to around 370 with a variable font, can rebalance it. Avoid going down to thin weights.
Yes. The same ratios apply: 4.5:1 for normal text and 3:1 for large text at Level AA. Test your dark palette separately from your light one.
It depends on the reader and the situation. Many people read long text more comfortably in light mode, while others prefer dark mode, especially in low light. Offering both and respecting the user's choice is the best approach.
A very dark grey rather than pure black, such as #121212 or a similar near-black with a slight tint that suits your brand. It reduces glare and leaves room for lighter surfaces to show elevation.
Changing font weight usually changes letter widths. Use a variable font with a grade axis if possible, which changes thickness without changing width, or keep weight the same in both themes.
Conclusion
Dark mode changes how typography is perceived. Light text on a dark background looks bolder and brighter, and at very high contrast it can glow and blur for some readers. The fix is a set of small, deliberate adjustments: a dark grey background instead of pure black, off-white text instead of pure white, slightly reduced weight, a little extra spacing, and lighter, softer accent colours for links and highlights.
Build those adjustments into colour tokens and a few media queries or a theme attribute, keep every pairing above WCAG's thresholds without chasing maximum contrast, and test with real reading on real screens. Done well, dark mode typography feels as calm and readable as your light theme, rather than a simple inversion of it.


