Going Dark (Mode)

If you can’t sweat the small things on your own website, then why even have your own website in the first place?
A photograph of a body of water illuminated by a full moon that's partially obscured behind some clouds
(Kyle Johnson)

I spent this past weekend adding something to Opus that I’ve been planning for awhile. You can now toggle the site between “light” and “dark” modes via the sun/moon switch in the site’s main menu.

I’m not a “dark mode” user myself — light text on a dark background tends to mess with my eyes and give me a headache — but I know many prefer it, and thanks to the beauty of modern CSS (e.g., CSS variables), it was pretty easy to implement. That’s not to say there were no challenges, though.

For starters, creating a “dark” version of your site’s theme isn’t simply a matter of just inverting the colors. That’s an obvious place to start, though you’ll likely end up finessing your colors a bit. Colors are tricky things, after all. Combinations that are technically correct on paper might not actually look good on-screen, and thus require some counterintuitive adjustments. That’s even more so if you want to ensure proper color contrasts for accessibility purposes — which should be the case.

As a result, I ended up making subtle changes across the whole of Opus’ color palette. The site’s “light” theme is predominantly gray with slight hints of blue. When I started inverting the site’s colors, however, I saw that some of the grays were actually a bit on the purple side, and therefore needed to be dialed back. (Sorry, purple fans.)

I also had to refactor parts of the site’s CSS and make greater use of CSS variables to define the color palette. And since I used several different ways to declare colors — standard hex, rgba, and 8-character hex (which includes two additional characters for specifying opacity) — those needed to be refactored and standardized, too.

This led to the discovery of my new favorite bit of CSS: the color-mix() function, which lets you blend two colors to varying degrees. For example, I could pass in a CSS color variable to create a transparent version of it:

color-mix(in srgb, var(--gray2) 0%, transparent)

That might seem superfluous, but it was useful for ensuring the consistency and smoothness of the gradients that appear throughout the site (e.g., in the header and footer).

I also had to modify some of the site’s SVG, specifically the icons used for the star ratings in the “Cultural Diet” section. For instance, the “empty” and “half” star icons had a light stroke that proved problematic in dark mode, so I just removed it. But that meant finding a new way to display “half” ratings. The solution I hit upon isn’t perfect, but it works for the time being (and gives me something to keep fiddling with.)

As for the actual dark mode toggling, I used Ryan Postell’s method — which takes into account both the user’s theme selection as well as their system settings — albeit with a few Opus-specific tweaks. After implementing his method, though, I encountered some unsightly “flash of inaccurate color theme” issues while navigating around in dark mode. Those happened because the site’s theme defaults to light mode, and only switches to dark mode on page load based on the user’s theme selection — a switch that, depending on the page, might take long enough to result in the aforementioned flash.

Fortunately, that was fixed by adding some vanilla JS to the site’s <head> that checks which mode has been enabled — either by the user’s selection or their system settings — and then adds the appropriate class to the <html> tag before the page is rendered. This ensures that the correct styles are applied before the user actually sees anything in their browser, eliminating the flash.

Most people probably wouldn’t notice these details, but if you can’t sweat the small things on your own website, then why even have your own website in the first place? In any case, adding dark mode to Opus was a fun experiment, and I hope it makes the site a bit more flexible and enjoyable for everyone.

Enjoy reading Opus? Want to support my writing? Become a subscriber for just $5/month or $50/year.
Subscribe Today
Return to the Opus homepage