Dark mode (or dark theme, depending on whom you ask) is a great thing, and major operating systems have adopted it in the past few years as a native feature: Windows, macOS, and Linux desktop environments such as GNOME, Xfce, and KDE have a dark mode built-in.
My personal favorite is to add the Night Theme Switcher extension to my installation of GNOME, and set it to automatic mode following the sunrise and sunset times. This way, every morning and every evening, as the sun rises or sets, my desktop gets brighter or darker, following the ambient light around me.
But these days we spend a lot of time on websites and web apps, and most of them have no idea that you might want to use a darker mode for reading or browsing. Some websites have a toggle triggering a change to a darker theme, but most of them don’t. Thankfully we have the Dark Reader extension for Firefox, Chrome, Edge, Safari (macOS and iOS alike), and even Thunderbird1 that can be set to automatically follow the system settings, and which changes the color palette of the current website accordingly. It’s not perfect, but it does and admirably good job in 99% of cases.
Of course, Dark Reader takes some decisions that web designers might disagree with, so what are they to do? Fear not: we’re almost in 2025, and we have broad browser support for the new light-dark()
CSS function.
I’ve added it to the very website you’re reading right now, and to De Programmatica Ipsum as well. With a recent browser, just by changing the theme setting of your operating system from light to dark, you will see these websites follow your preferences accordingly.
How does it work? Well, summarizing these instructions and adapting them to the Hugo theme I’m using here:
- Add the required meta tag in the
<head>
section of your page:
<meta name="color-scheme" content="light dark">
- Create SCSS variables for dark colors; I literally copied the colors proposed by Dark Reader using the Gcolor3 color picker for Linux. Simple!
- In the
config.toml
configuration file of your Hugo project, select a Chroma code highlighter style that looks good in both light and dark modes; in my case I chose “average”. - Use the
light-dark()
function to specify colors inbackground-color:
orcolor:
CSS rules, or wherever color information is expected, such as inborder
rules:
body {
background-color: light-dark($body-background-light, $body-background-dark);
color: light-dark($text-color-light, $text-color-dark);
}
.post-footer {
border-bottom: 1px solid light-dark($gray-light, $gray-dark);
}
…and you’re done. Your website will not happily switch automatically from one value to the other, every time your operating system decides it’s time to go dark or light. And your readers will thank you for that.
Bonus Track: JavaScript
If you would like to react from your JavaScript code to these theming changes, you can use this code (source):
// Listen to preference changes
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', event => {
redraw();
});
// Query the current theme
function getBackgroundColor () {
if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
return "black";
}
return "white";
}
Yes, Thunderbird has a dark mode built-in… but it does not affect the theme of the message pane (seriously?!), which stays stubbornly white, kinda defeating the whole point of a dark mode. The Dark Reader extension, thankfully, completes the feature. ↩︎