Welcome to the dark side

The previous incarnation of this website had a dark theme option, but when I did the redesign a year or so ago I did not get around to implementing it. I’m of course aware that a dark option is an important accessibility feature for many people, especially as I’m using dark mode, too.

That said, most websites do not implement dark mode, so having a browser plugin like Noir or Dark Reader is necessary anyway.

A few weeks ago I read through Hidde’s blog post on his dark mode toggle implementation and that gave me the impetus to change this website to support dark mode, too.

First, I was thinking of just copying his solution, but binary dark mode toggles have an important caveat: What happens when the user changes their system settings?

You can either not follow the user’s setting and keep their choice, or, you can adapt with the system. Hidde looks for the change event in the dark mode media query and then adapts to the system preference. However, that only works if the website is open. If the website is closed, there is no way to update the data on what theme to use.1

Essentially there are three modes that should be respected:

  • Follow the system setting at all times.
  • Use light mode all the time, even if the system is in dark mode.
  • Use dark mode all the time, even if the system is in light mode.

Looks like a 2-way toggle is not going to cut it. And while I briefly thought about a tri-state button2 , there is only so much information that you can convey through one button. I looked around and Hidde’s post already had the Firefox settings which showed “System theme”, “Light” and “Dark” with radio buttons. And macOS is doing a similar thing in the system preferences3 .

Screenshot from macOS Monterey System Preferences, showing Light, Dark, Auto as “Appearance” options.

When in doubt, I always prefer to be clear instead of clever, so my preferences button in the top right follows about the same principle. I use the new <dialog> element to put up a dialog that lets users choose their theme. A nice advantage of using a dialog is that users can get a preview of the changes and can then decide to save their choice or cancel and use their previous choice.

Of course there are a few caveats with this solution, not last the one Hidde also mentions in his post: To make it work reliably, I need to duplicate my variable declarations in my CSS file:

:root { /* Default light colors */ }

:root[data-theme-preference="light"] { /* Light theme selected */ }

@media (prefers-color-scheme: dark) {
  :root { /* System dark mode */ }

:root[data-theme-preference="dark"] { /* Dark mode selected */ }

The JavaScript is basically equivalent with a lot of what Hidde does, apart from the theme preference also supporting the value system. I also added a short inline JavaScript right after the opening <body> tag that applies the theme data attribute as soon as possible on page load. As my JavaScript is in a separate file, you could have gotten a flash of white before the dark mode kicked in.4

I would agree with Hidde and Bramus that browsers should offer users choice between themes (and let’s extend it beyond light & dark, please! Despite the title of this post, this is not Star Wars!)

  1. As I write this I realize that a Service Worker might be a way to do it, but that feels like an overengineered solution…
  2. Urgh!
  3. Until macOS 12 Monterey at least, macOS 13 Ventura introduces a new preferences app, which has been rated “meh” so far. Let’s hope the best for improvements during the beta.
  4. That makes me wonder, what if we could use localStorage in media queries? For example: @media(localStorage("theme-preference"): dark)? That would be useful!

Tags: ,

Language: English

Comments & Webmentions


Comments were disabled on this page.

Preferences (beta)

Select a Theme
Font Settings

Preferences are saved on your computer and never transmitted to the server.