Light & Dark theme
I’ve added a light/dark mode and a theme switcher to this website now (in the footer). I expect I’ll make some tweaks to the colour-scheme in time to improve the legibility & accessibility of the website.
The rest of this post explains how I implemented it.
Step 1: Add some media-queries into the CSS.
The easiest way to add dark/light theme support is with the CSS media feature
prefers-color-scheme
.
Using this media feature, you can specify different CSS styles based on user preference which is set at either OS or browser level.
@media (prefers-color-scheme: dark) {
/* Dark styles go here */
}
@media (prefers-color-scheme: light) {
/* Light styles go here */
}
Whilst I could have stopped there, I wanted to give users the option of changing the theme on-the-fly.
Unfortunately, there’s not an easy way to change this ‘prefers-color-scheme’ setting on a per website basis1. This means individual websites have to implement their own mechanism to support it.
Step 2: Add some Javascript.
In order for the user to be able to switch the theme, I’ve had to include
some Javascript into each page. This will apply an extra CSS class onto the
body
tag of the page, adjusting the styles to switch between light & dark
themes.
Unfortunately the way I’ve implemented this means that I need to duplicate
the CSS for both dark & light colour-schemes.
I apply a .light
class if prefers-color-scheme: dark
, and a .dark
class where prefers-color-scheme = light
or unset).
:root {
/* (Default) light styles go here */
}
:root.dark {
/* Dark styles go here */
}
@media (prefers-color-scheme: dark) {
:root {
/* (Default) dark styles go here */
}
:root.light {
/* Light styles go here */
}
}
The above CSS is paired with the following Javascript code, which toggles between light & dark themes:
/* Identify the user preference */
var darkMode = false;
if ( window.matchMedia && window.matchMedia("(prefers-color-scheme: dark)").matches ) {
var darkMode = true;
}
/* Toggle the colour-scheme */
if (darkMode) {
document.documentElement.classList.toggle("light");
} else {
document.documentElement.classList.toggle("dark");
}
This is a good start, but when you navigate to a different page, or refresh
the website the styles will revert to the prefers-color-scheme
preference.
That’s bad UX.
We need a way to retain the users choice for the session.
Step 3: Persistance.
How can we store the user preference without a backend? Store it on their device.
I’ve used a localStorage
variable. When a user navigates to this website the
default value is set to their current preference. If they toggle the
colour-scheme, that variable is updated, and checked on each new page-load to
apply the correct colour-scheme for the next visit, or page click.
const sessionMode = localStorage.getItem("darkmode");
if ( sessionMode == null) {
/* Store the default value */
localStorage.setItem("darkmode", darkMode);
} else {
if ( sessionMode == "false" ) {
/* Toggle .light class */
document.documentElement.classList.toggle("light");
} else {
/* Toggle .dark class */
document.documentElement.classList.toggle("dark");
}
}
During testing, I had some of this code in a function which waited until the
DOM content had finished loading, but this caused a flash-of-unstyled-text
(FLOUT). I was also weary of the page-length, or load-times if the script was
loaded from an external file, so I added the critical Javascript into the
<head>
of the page which minimises the chance of that happening.
I wonder if there’s browser addons that add this ability, or if that would be possible… ↩︎
- Author:
- Jonathan Street
- Permalink:
- https://jstreet.uk/light-dark-theme/
- Published: