Dark mode has gone from niche preference to baseline expectation. Most operating systems, browsers, and major apps ship with it. Users who switch tend to keep it on permanently. For websites, a dark theme is no longer a nice-to-have.
But dark mode is not "swap white for black and ship." A bad dark theme is harder to read than no dark theme at all. Colors, contrast ratios, shadows, and visual hierarchy all need rework for dark backgrounds. Getting it right takes deliberate design work, not a global filter.
Why Dark Mode Is More Than Inverting Colors
The most common mistake is inverting the color scheme: white becomes black, black becomes white. This creates several problems.
Pure black (#000000) backgrounds with pure white (#ffffff) text create too much contrast. On OLED screens, the stark boundary between lit and unlit pixels creates a visual vibration effect that strains the eyes. This is called "halation" and it makes long text passages uncomfortable to read.
Colors that look vibrant on a light background can look garish on a dark one. A saturated blue (#2563eb) that looks professional on white backgrounds becomes visually aggressive on dark gray. Dark mode colors need to be desaturated and slightly lighter to maintain the same perceived vibrancy.
Shadows stop working. On light backgrounds, shadows create depth by darkening the area below an element. On dark backgrounds, dark shadows are invisible. You need to either use lighter shadows, subtle borders, or slight color differences to create depth.
The Color Picker helps you find colors that work specifically for dark themes. Start with your light-mode palette and adjust each color: reduce saturation by 10-20% and increase lightness by 10-15% for backgrounds and accents.

Choosing Your Dark Mode Color Palette
A good dark mode palette uses dark grays rather than pure black. Here is a proven foundation:
Backgrounds: Use a range of dark grays instead of a single black.
- Page background: #0f172a (very dark blue-gray) or #111827 (neutral dark gray)
- Surface (cards, modals): #1e293b or #1f2937
- Elevated surface (popovers, dropdowns): #334155 or #374151
Text: Pure white (#ffffff) on dark gray is acceptable for headings but too bright for body text.
- Primary text: #f1f5f9 or #f3f4f6
- Secondary text: #94a3b8 or #9ca3af
- Disabled text: #475569 or #6b7280
Accents: Desaturate your brand colors by 10-20% for dark mode.
- Instead of #2563eb (vivid blue), use #3b82f6 (slightly lighter, less saturated)
- Instead of #dc2626 (vivid red), use #ef4444
The Contrast Checker verifies that your text-to-background combinations meet WCAG accessibility standards. Dark mode needs a minimum contrast ratio of 4.5:1 for normal text and 3:1 for large text. Check every color combination, not just the primary ones.
Use the Gradient Generator if your light theme uses gradients. Dark mode gradients should be subtler, with less color variation and lower opacity. A dramatic blue-to-purple gradient on a light background should become a muted dark-blue-to-dark-purple on a dark background.
A good dark mode palette uses dark grays rather than pure black.
CSS Implementation with Custom Properties
The cleanest way to implement dark mode in CSS is with custom properties (CSS variables) and the prefers-color-scheme media query.
`css
:root {
--bg-primary: #ffffff;
--bg-surface: #f9fafb;
--bg-elevated: #f3f4f6;
--text-primary: #111827;
--text-secondary: #6b7280;
--border: #e5e7eb;
--accent: #2563eb;
--shadow: rgba(0, 0, 0, 0.1);
}
@media (prefers-color-scheme: dark) {
:root {
--bg-primary: #0f172a;
--bg-surface: #1e293b;
--bg-elevated: #334155;
--text-primary: #f1f5f9;
--text-secondary: #94a3b8;
--border: #334155;
--accent: #3b82f6;
--shadow: rgba(0, 0, 0, 0.4);
}
}
`
Every component references these variables instead of hard-coded colors:
`css
.card {
background: var(--bg-surface);
color: var(--text-primary);
border: 1px solid var(--border);
box-shadow: 0 2px 8px var(--shadow);
}
`
This approach requires zero changes to your component CSS when switching themes. The variables handle everything.
For a manual toggle (letting users choose regardless of system preference), add a data attribute:
`css
[data-theme='dark'] {
--bg-primary: #0f172a;
/ ... all dark overrides /
}
`
Toggle data-theme on the element with JavaScript, and persist the choice in localStorage so it survives page refreshes.
Images and Media in Dark Mode
Images designed for light backgrounds often look jarring on dark ones. A product photo with a white background, a screenshot of a light-themed app, or a diagram with light gray fills will all appear as bright rectangles floating on your dark interface.
Several strategies help:
Reduce image brightness. Apply a subtle CSS filter to images in dark mode:
`css
@media (prefers-color-scheme: dark) {
img:not([src*='.svg']) {
filter: brightness(0.85);
}
}
`
This dims photographs just enough to reduce the contrast against the dark background without making them look washed out.
Provide dark-mode-specific images. For screenshots and diagrams, the element with prefers-color-scheme media queries lets you serve different images per theme:
`html
`
SVG icon color adaptation. If your icons use currentColor, they automatically match the text color in both themes. If they use hard-coded fill colors, override them in dark mode.
Transparent backgrounds for logos. Always use PNG or SVG logos with transparent backgrounds. A logo on a white rectangle looks terrible on a dark page.
Video and embedded content. These are harder to adapt. If you embed light-themed third-party content (CodePen, Figma, tweets), there is usually no way to force their dark mode. Accept that some embedded content will have light backgrounds and ensure it has enough padding to not look broken.

Testing Dark Mode Thoroughly
Dark mode introduces edge cases that light mode never encounters. Test these scenarios specifically:
Form elements. Browser default form controls (inputs, selects, checkboxes) have different default styling in dark mode depending on the browser and OS. Custom-styled form elements need explicit dark mode colors. Placeholder text color, focus ring color, and error state colors all need dark mode variants.
Third-party widgets. Chat widgets, analytics banners, cookie consent popups, and embedded content often have their own color schemes that clash with your dark theme.
Hover and focus states. A hover effect that lightens a button by 10% on a light background needs to lighten by 10% on a dark background too, but from a different base color. Check every interactive element.
Scrollbars. On some operating systems, scrollbar appearance changes with the color scheme. On others, it stays light regardless. Use color-scheme: dark in your CSS to hint the browser to use dark scrollbars.
Print styles. Users who print from dark mode should get a light-themed printout. Add @media print rules that override dark mode variables with light values.
Test in multiple browsers (Chrome, Firefox, Safari) and on multiple operating systems. Dark mode rendering varies more across platforms than light mode because implementations are newer and less standardized.
Common Dark Mode Design Mistakes
Using pure black (#000000). It creates excessive contrast with text and causes halation on OLED screens. Use dark gray (#111827 or #0f172a) instead.
Not adjusting shadow intensity. Shadows that work at rgba(0,0,0,0.1) on light backgrounds are invisible on dark backgrounds. Increase the opacity to rgba(0,0,0,0.3) or rgba(0,0,0,0.4), or use a different depth technique entirely (borders, subtle background differences).
Keeping the same accent color saturation. Fully saturated colors (hue at 100% saturation) vibrate against dark backgrounds. Reduce saturation by 15-20% or increase lightness slightly.
Forgetting about disabled and inactive states. Light gray disabled text on white (#d1d5db on #fff) needs a completely different color on dark (#4b5563 on #1e293b). The relative contrast must be maintained, not the absolute color values.
Not persisting the user's choice. If a user manually selects dark mode, that preference should survive page refreshes, new tabs, and future visits. Store the preference in localStorage and apply it before the page renders to avoid a flash of the wrong theme.
Flash of incorrect theme (FOIT). If dark mode is applied via JavaScript after the page loads, users see a brief flash of the light theme. Apply the theme class in a
**Using pure black (#000000).** It creates excessive contrast with text and causes halation on OLED screens.
FAQ
Does dark mode save battery?
On OLED and AMOLED screens, yes. These displays turn off individual pixels that are pure black, which reduces power consumption. On LCD screens, the backlight stays on regardless of what is displayed, so dark mode has no battery benefit. Since most modern phones use OLED, dark mode does provide a practical battery advantage for mobile users.
Should I default to dark mode or light mode?
Default to the user's system preference using prefers-color-scheme. If no preference is detected, default to light mode. This respects user choice without forcing a preference. Always provide a manual toggle so users can override the system setting.
Is dark mode better for accessibility?
Not universally. Some users with visual impairments find dark mode easier to read (less glare, reduced eye strain in low light). Others, particularly those with astigmatism, find light text on dark backgrounds harder to read because of halation. The best approach for accessibility is offering both options and letting users choose.
How do I handle dark mode in email templates?
Email clients handle dark mode inconsistently. Outlook inverts colors automatically, Gmail respects prefers-color-scheme in some contexts, and Apple Mail handles it well. For reliable email dark mode, use transparent images, test in multiple clients, and provide both a prefers-color-scheme: dark block and inline dark mode fallbacks.
CSS Layout Tools: Grid, Flexbox, Gradients and Shadows
A practical guide to CSS Grid, Flexbox, gradients, and box shadows. Learn when to use each layout technique and generate clean CSS code fast.
Edit Images in Your Browser: Resize, Compress, Convert
Handle common image tasks in your browser without installing software. Resize, compress, convert formats, and inspect EXIF metadata in seconds.
CSS Generators: Gradients, Flexbox, Grid and Shadows
Use CSS generators to create gradients, flexbox layouts, grid systems, and box shadows. Visual editors output ready-to-copy CSS for your project.
