Dark Mode Icon Design
Published on
Dark mode is no longer a niche preference. Modern applications are expected to handle it cleanly, and icons have to work in both light and dark contexts without demanding a separate set for every theme.
The problems dark mode exposes
Icons tend to show their weak points as soon as the interface flips to a dark background. Contrast inverts, colours read differently, and bright elements start to feel harsher. Shadows stop behaving the way they did on white. Brand colours may need tuning as well, which is where a lot of teams discover that their original icon system was only ever designed for one background.
Approaches that hold up across themes
There are a few practical ways to make icons adapt. The simplest is to let them inherit text colour with currentColor. That works neatly for monochrome icons and avoids extra assets.
<svg fill="currentColor" viewBox="0 0 24 24">
<path d="..."/>
</svg>
/* CSS */
.icon {
color: var(--text-color);
}
:root {
--text-color: #1a1a1a;
}
[data-theme="dark"] {
--text-color: #f0f0f0;
}Multi-colour icons need more care. CSS custom properties let each part of the SVG respond to the current theme without rebuilding the asset, which is usually the cleanest way to keep a set maintainable.
<svg viewBox="0 0 24 24">
<path fill="var(--icon-primary)" d="..."/>
<path fill="var(--icon-secondary)" d="..."/>
</svg>
:root {
--icon-primary: #333;
--icon-secondary: #666;
}
[data-theme="dark"] {
--icon-primary: #fff;
--icon-secondary: #aaa;
}CSS filters are the quick option. They are useful when you need a fast pass over simple icons, but coloured icons can produce odd results. Good enough, sometimes. Ideal, not really.
[data-theme="dark"] .icon {
filter: invert(1);
}
/* Or for more control */
[data-theme="dark"] .icon {
filter: brightness(0) invert(1);
}Colour changes that usually matter
In dark mode, highly saturated colours often feel louder than they do on a light background. Reducing saturation by 10-20% is a sensible starting point for dark mode variants. Pure white can also be too sharp, so off-white such as #f0f0f0 is often easier on the eye. The same logic applies in reverse for colours that become too dark to read. Keep contrast honest. Aim for at least 3:1 between icon and background.
Depth, shadow and dimensional effects
Traditional shadow treatment needs rethinking once the background is dark. Glows often work better than drop shadows, or you can use lighter shadow colours. Gradients may need their direction reversed or their colours adjusted. If overlapping elements start blending together, a subtle stroke can separate them. Three-dimensional effects are the most likely to look clumsy, so flattening them or swapping shadow for highlight is usually the cleaner move.
Duotone icons need separate judgement
Duotone sets are rarely a straight colour swap. The primary colour usually needs brightening, while the secondary colour, often running at lower opacity, can disappear completely. Sometimes the better answer is to reverse which part reads as primary and secondary. Opacity values may need adjustment too. That is the trade-off with duotone: more character, more maintenance.
Testing before the dark mode ships
Good testing catches the obvious misses early. Check OS-level dark mode, then your in-app theme toggle, because those do not always behave the same way. Review icons against the actual background colours used by the interface. Test at different screen brightness levels and on different displays. Accessibility tools should confirm the contrast ratios rather than relying on visual judgement alone.
Detecting the active theme
User preference is usually handled through the system setting, with prefers-color-scheme doing the heavy lifting. CSS can switch variables directly, and JavaScript can read the same preference if the interface needs it.
/* Detect system preference */
@media (prefers-color-scheme: dark) {
:root {
--icon-color: #f0f0f0;
}
}
/* Or in JavaScript */
const darkMode = window.matchMedia(
'(prefers-color-scheme: dark)'
).matches;Dynamic styling or separate variants?
The right approach depends on how much control the icon set needs. Dynamic styling through CSS keeps maintenance lower and theme switching instant, but it gives up some control. Separate variants give maximum control, at the cost of more files and loading logic. A hybrid setup is often the practical compromise: dynamic styling for most icons, variants for the awkward ones.
For most icon sets, CSS variables give the best balance of flexibility and maintenance.
Animated icons still need theme checks
Animation does not exempt an icon from dark mode rules. Colour transitions should use theme-appropriate values, glow effects may need less intensity, and reduced motion preferences should be considered alongside dark mode rather than treated as a separate problem.
Document the system, not just the assets
The icon treatment should be documented clearly: which method or methods the icons support, the CSS variable names and theme values, any icons that need special handling, and the test checklist for new additions. That saves time later, and it stops every new icon from becoming a small debate.
Clear documentation helps team members implement icons correctly across themes.