Creating a dark mode (for this tiny personal site) was way easier than I thought it was going to be. It had been a loose idea of mine for a long time, but it wasn’t nearly as bad as I expected, and I shouldn’t have put it off. All told, it took under an hour.
This site is a mostly-cobbled-together collection of scripts, custom handwritten CSS, and a tiny sprinkling of JavaScript. That kind of bespoke code means it’s quite fun and easy to tinker with things, but changes can turn into nested layers of “fixes” pretty quickly.
The key things I wanted dark mode to do were these:
CSS variables are essentially the answer to “make modes easily
interchangeable”. For whatever reason, I mistakenly believed that CSS
variables required a preprocessor like SASS or LESS; they don’t. The key
is adding a light-mode
or dark-mode
class full
of color variables to the html
element, and then switching
between these classes. For example, I now have classes that look like
these:
.light-mode {
--text-color: #333333;
--body-background: whitesmoke;
--primary-color: #2faced;
}.dark-mode {
--text-color: #bbbbbb;
--body-background: #0a0a0a;
--primary-color: #09547b;
}
body {background: var(--body-background);
color: var(--text-color);
}
This required a slight refactor, mostly just searching for colors (a
#......
regex worked fine) and extracting them into light
mode variables, then adding their dark mode equivalents. Now, when I
manually added a dark-mode
or light-mode
class
to the html
element, I could see the modes switch before my
eyes.
The answer to “don’t use a database” is “use
localStorage
”. If someone has their mode saved in
localStorage
, I use that to set the mode. However, I
additionally wanted to respect people’s preferences upon the very first
load of a page. For this, we can use
window.matchMedia("(prefers-color-scheme: light)").matches
to find whether someone prefers a light color scheme, otherwise set it
to be dark.
Here’s some (un-minified) JavaScript to do that:
var mode = localStorage.getItem('mode')
document.getElementsByTagName('html')[0].setAttribute('class',
mode? mode
: ( window.matchMedia("(prefers-color-scheme: light)").matches
? 'light-mode'
: 'dark-mode'
) )
Finally, I wanted a toggle that would allow people to change the
scheme they preferred on the fly (and save their preference in
localStorage
). Another tiny piece of JavaScript:
var mode = localStorage.getItem('mode') === 'light-mode' ? 'dark-mode' : 'light-mode'
document.getElementsByTagName('html')[0].setAttribute('class', mode)
.setItem('mode', mode) localStorage
Try it out!