Dark mode has evolved from a trendy feature to a user expectation. It reduces eye strain in low-light environments, saves battery on OLED screens, and provides an alternative aesthetic that many users prefer. Implementing dark mode correctly, however, involves more than inverting colors—it requires a systematic approach to theming that handles images, shadows, contrast, and user preferences. At Nexis Limited, we build robust theme switching systems that delight users and maintain design integrity.
Architecture with CSS Custom Properties
The foundation of any theme switching system is CSS custom properties (CSS variables). We define a complete set of semantic color tokens as custom properties on the root element, then override them for dark mode. The light theme might define --color-bg-primary: #ffffff and --color-text-primary: #1a1a1a, while the dark theme swaps these to --color-bg-primary: #121212 and --color-text-primary: #e0e0e0. Components reference only these semantic tokens, never raw color values.
We apply the dark theme by toggling a data attribute on the HTML element—data-theme="dark"—and using attribute selectors to override the custom properties. This approach is more flexible than class-based toggling because it allows nested theme contexts and component-level theme overrides.
Color Science for Dark Mode
Dark mode is not simply inverting light mode colors. Material Design guidelines recommend using dark gray (#121212) rather than pure black (#000000) for backgrounds, as pure black creates excessive contrast that causes eye fatigue. Surfaces in dark mode use elevated shades of gray to communicate depth—a card floating above the background should be slightly lighter than the background itself. We define 4-5 surface elevation levels, each progressively lighter, to maintain the visual hierarchy.
Text colors in dark mode should not be pure white. We use off-white values like #e0e0e0 for primary text and #a0a0a0 for secondary text. This softens the contrast and reduces the harshness of reading on dark backgrounds. Accent colors often need adjustment too—vibrant colors that work on white backgrounds may appear oversaturated on dark backgrounds and need desaturation.
Detecting System Preferences
The prefers-color-scheme media query detects the user's operating system theme preference. In CSS, @media (prefers-color-scheme: dark) applies dark mode styles when the OS is in dark mode. In JavaScript, window.matchMedia('(prefers-color-scheme: dark)') provides programmatic access. We listen for changes using the change event on the matchMedia query, so the app responds immediately when the user toggles their system theme.
Three-State Toggle: Light, Dark, System
The best theme switching UI offers three options: light, dark, and system (auto). The system option respects the OS preference while the explicit light and dark options override it. We store the user's choice in localStorage and apply it on page load before the first paint to prevent a flash of incorrect theme (FOIT). This requires a small inline script in the document head that reads localStorage and sets the data attribute before the stylesheet renders the page.
Handling Images and Media
Images designed for light backgrounds often look jarring on dark surfaces. We use the picture element with media attributes to serve alternate images for dark mode. For decorative images and illustrations, CSS filters like filter: brightness(0.8) contrast(1.1) can adjust visual weight without requiring separate assets. SVG icons should use currentColor for their fill or stroke so they automatically adapt to the surrounding text color.
Smooth Theme Transitions
Abrupt color changes when switching themes feel harsh. We add a brief CSS transition on the root element—transition: background-color 200ms ease, color 200ms ease—to create a smooth crossfade. However, this transition should only apply during user-initiated theme changes, not on page load. We achieve this by adding a transition-enabling class momentarily during the switch and removing it after the transition completes.
Dark mode done right enhances usability and demonstrates technical polish. Contact us to implement a robust theming system in your web application. See themed applications in our portfolio.