How to Add Dark Mode Without Breaking Your HTML
Respect system preferences, preserve contrast, and keep native controls and embedded content legible in both themes.
The short version
Dark mode is a complete color system, not an inverted background.
Declare that both schemes are supported
The color-scheme property tells the browser which schemes your page can render. That helps native controls, scrollbars, and form fields match the surrounding interface.
:root {
color-scheme: light dark;
--surface: #fafaf7;
--text: #151513;
}
@media (prefers-color-scheme: dark) {
:root {
--surface: #151513;
--text: #e8e8e2;
}
}Design each role, not each hex value
Map colors to jobs such as surface, text, muted text, border, action, warning, and focus. Review the relationship between those roles in both modes. Pure white on pure black can feel harsher than a tuned near-white and near-black pair.
Test the awkward parts
If you offer a manual switch, save the preference locally and apply it before the page becomes visible to avoid a theme flash. The system preference remains a sensible default for first-time visitors.
- Form controls and validation states.
- Code blocks, charts, and screenshots.
- Logos with transparent backgrounds.
- Focus indicators and text selection.
- Printed output, which usually needs a light theme.