How would you implement dark mode and light mode?

Dark Mode and Light Mode
Implementing dark mode and light mode in a web application improves accessibility, reduces eye strain in low-light environments, and gives users control over their experience. The most modern and elegant approach is using the light-dark()
CSS function, which became available in browsers in May 2024.
Modern Approach: light-dark()
The light-dark()
function is a revolutionary way to implement theme switching. It allows you to specify both light and dark theme colors directly in your CSS properties without complex media queries or JavaScript.
How It Works
The light-dark()
function takes two color values:
- The first color is used when the user's preference is set to light mode (or if no preference is set)
- The second color is used when the user's preference is set to dark mode
Enable Color Scheme Support
First, enable support for both light and dark color schemes:
:root {
color-scheme: light dark;
}
Apply Colors Using the light-dark()
Function
Use the function directly in your CSS properties:
body {
color: light-dark(#333333, #e0e0e0);
background-color: light-dark(#ffffff, #121212);
}
.button {
background-color: light-dark(#0066cc, #4d9fff);
color: white;
}
.card {
background-color: light-dark(#f2f2f2, #2a2a2a);
border: 1px solid light-dark(#cccccc, #444444);
}
Add Smooth Transitions (Optional)
For a polished user experience, add transitions as shown below:
* {
transition: background-color 0.3s ease, color 0.3s ease, border-color 0.3s ease;
}
That's it! Your website will automatically switch between light and dark mode based on the user's system preferences.
CSS Variables for Better Organization
For larger projects, you can combine the light-dark()
function with CSS variables:
:root {
color-scheme: light dark;
/* Define theme colors */
--light-background: #ffffff;
--light-text: #333333;
--light-primary: #0066cc;
--light-secondary: #f2f2f2;
--light-accent: #ff6b00;
--dark-background: #121212;
--dark-text: #e0e0e0;
--dark-primary: #4d9fff;
--dark-secondary: #2a2a2a;
--dark-accent: #ff9d4d;
}
body {
background-color: light-dark(var(--light-background), var(--dark-background));
color: light-dark(var(--light-text), var(--dark-text));
}
.button {
background-color: light-dark(var(--light-primary), var(--dark-primary));
}
.card {
background-color: light-dark(var(--light-secondary), var(--dark-secondary));
border: 1px solid light-dark(var(--light-accent), var(--dark-accent));
}
Adding User Control with JavaScript (Optional)
While the CSS-only approach respects system preferences, you might want to give users the ability to toggle between light and dark mode.
<button id="theme-toggle" aria-label="Toggle dark mode">
Toggle Dark Mode
</button>
// Get the toggle button
const themeToggle = document.getElementById('theme-toggle');
// Simple function to toggle between light and dark
function toggleTheme() {
// Get the current color scheme preference
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
// Set the opposite of the system preference
const newTheme = prefersDark ? 'light' : 'dark';
// Apply the theme
document.documentElement.setAttribute('color-scheme', newTheme);
// Save preference to localStorage
localStorage.setItem('theme', newTheme);
}
// Add click event to button
themeToggle.addEventListener('click', toggleTheme);
// Initialize theme on page load
function initializeTheme() {
const savedTheme = localStorage.getItem('theme');
if (savedTheme) {
document.documentElement.setAttribute('color-scheme', savedTheme);
}
}
// Call on page load
initializeTheme();
Why This Approach Is Superior
-
Simplicity: Minimal code required compared to traditional approaches.
-
Locality: Colors for both themes are defined right where they're used.
-
Zero JavaScript Required for basic functionality that respects system preferences.
-
No Duplication: You don't need to repeat selectors for different themes.
-
Automatic Updates: The theme changes automatically when the user changes their system preference.
-
No Flash of Incorrect Theme: The correct theme is applied immediately on page load.
Fallback for Older Browsers
For browsers that don't support the light-dark()
function, you can provide a fallback using feature detection:
@supports not (color: light-dark(black, white)) {
:root {
--background: #ffffff;
--text: #333333;
}
@media (prefers-color-scheme: dark) {
:root {
--background: #121212;
--text: #e0e0e0;
}
}
body {
background-color: var(--background);
color: var(--text);
}
}
Interview Tips
When discussing this approach in an interview:
-
Demonstrate Modern Knowledge: Mentioning the
light-dark()
function shows you stay current with web development trends. -
Explain Progressive Enhancement: Discuss how you'd handle older browsers that don't support this feature.
-
Mention Accessibility: Explain how respecting user preferences improves accessibility.
-
Discuss Performance: Point out that this approach is more performant than alternatives that require more JavaScript.
-
Framework Integration: If asked, explain how this approach can be integrated with React, Vue, or Angular.
Conclusion
The light-dark()
CSS function represents the most elegant and efficient way to implement dark mode and light mode in modern web applications. It simplifies the code, improves performance, and provides a better user experience by respecting system preferences while still allowing for user overrides when needed.
This approach demonstrates a deep understanding of modern CSS capabilities and a commitment to creating accessible, user-friendly web experiences.