- #css
- #javaScript
Introduction to dark mode
Looking around the web I think perhaps that it is only web developers who are obsessed with a dark mode for their websites and apps. For example, there is no dark mode available on the BBC, New York Times and Washington Post websites. There is on MDN Docs, Vercel, Svelte, React, Vue, Tailwind and Bootstrap websites! So how is a dark mode created with CSS and JavaScript?
HTML for dark mode
On the websites with a dark theme there is a common method. A sun icon to click on is shown in dark mode, whereas a moon icon is displayed in light mode. In this example I downloaded sun and moon icons as .svg files from Bootstrap icons into a project folder called images.
The HTML is quite simply 2 images inside a button:
<button class="darkmode-button">
<img src="./img/sun.svg" alt="sun icon" class="sun hide">
<img src="./img/moon.svg" alt="moon icon" class="moon">
</button>
For accessibility (a11y) reasons each img tag is provided alternative (alt) text and each image are enclosed within HTML button tags.
CSS for dark mode
Notice that the sun icon has a class of ‘hide’. In the CSS file, the .hide class has a display of ‘none’. It is this hide class that will be toggled on a click of the button.
.hide {
display: none;
}
In this example a light mode is the default, therefore the body CSS is:
body {
background-color: #f5f5f5;
color: #333;
}
And a dark theme class is prepared to invert the background and font colors:
body.dark-theme {
background-color: #333;
color: #f5f5f5;
}
That’s it for the CSS. Now for a smatter of JavaScript to make things work 👀
JavaScript for dark mode
The beauty of JavaScript is that problems can be solved in a mulitude of ways. Here is how I added the dark mode and light mode interactivty primarily with the sun / moon icon button.
To follow through the code you will also need to refer to the HTML and CSS above. At the beginning of my app.js script file, I created a darkTheme variable without a value and a ui (user interface) object that hooked up the sun and moon image icons with .querySelector.
let darkTheme;
const ui = {
sun: document.querySelector('.sun'),
moon: document.querySelector('.moon')
}
At the end of the app.js script file, I added an event listener on the button containing the sun and moon icons. If clicked this button, with a class of darkmode-button, would instantiate the toggleTheme function.
document.querySelector(`.darkmode-button`).addEventListener('click', toggleTheme)
Here is what the page looks like so far. A moon icon to click on!
JavaScript functions
In my learning of JavaScript I always remember, though do not always practise, that functions should only do one thing. In this example I took this approach.
Dark mode interactivity
Toggle theme
On a click of the button, the toggleTheme function is called. As described it toggles the darkTheme variable from false to true and vice versa. Having perfomed the toggle the browser’s local storage is updated with the user’s preferred darkTheme.
function toggleTheme() {
darkTheme = !darkTheme;
localStorage.setItem('usersTheme', JSON.stringify(darkTheme))
changeColors()
changeIcons()
}
After the darkTheme has been changed the changeColors and changeIcons functions need to be called.
Add and remove dark theme
The changeColors function uses a ternary operator to add or remove the dark-theme from the document body.
function changeColors() {
darkTheme ?
document.body.classList.add('dark-theme') :
document.body.classList.remove('dark-theme')
}
Toogle the sun and moon icons
And of course, the icons need to be switched from sun to moon and vice versa.
function changeIcons() {
if (darkTheme) {
ui.sun.classList.remove('hide')
ui.moon.classList.add('hide')
} else {
ui.sun.classList.add('hide')
ui.moon.classList.remove('hide')
}
}
Finishing touches
All the interactivty has been added to make the light/dark mode work. But there is a problem. If a user revisits the website the previous light/dark preference will not be remembered. Therefore a check of the browser’s localStorage needs to made when the website loads.
Beneath the variable declarations at top of the script file, a check of the localStorage needs to be made, setting the darkTheme boolean accordingly. Then, of course, changing the colors and icons as described.
if (JSON.parse(localStorage.getItem('usersTheme'))) {
darkTheme = true
} else {
darkTheme = false
}
changeColors()
changeIcons()
That’s it.
Thank you for stumbling across this website and for reading my blog post entitled CSS and JavaScript for website dark mode