Polishing my dark mode toggle 

Tags :

Earlier this year, I finally added a proper theme switch to the navigation of my website. Up until then, if relied on the visitor’s system’s setting prefer-color-scheme and didn’t provide a convenient way of switching between themes other than via a link in the footer to turn dark mode on.

Screenshot of my light mode navigation bar displaying the them toggle as a sun
Light mode
Screenshot of my dark mode navigation bar displaying the them toggle as a moon crescent
Dark mode
The solution I implemented was inspired by a couple of blog posts which addressed most of my concerns:

Setting the page’s theme colour

The theme colour of the page can be set in a couple of ways.

  1. Honouring the system appearance preference { light | dark | auto }
  2. Reading the web site’s user settings from localStorage { light | dark }

The challenge is to honour the visitor’s preferences while avoiding a flash of colour if the setting doesn’t match the default. My website defaults to light, but if the visitor has set his preferences to dark, the dark theme must kick in as early as possible to prevent a flash of yellow.

The theme is set via a data attribute in the html element data-theme="{ light | dark }".

<html class="js page page--post" lang="en-GB" data-theme="light">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
    <meta name="mobile-web-app-capable" content="yes">
    <script src="/js/theme-toggle-min.js"></script>

On page load, a small JS script checks the browser’s localStorage for existing preferences and sets the appropriate theme if present. If absent, it checks the visitor’s system preferences and sets the theme accordingly.

Why theme-color is important on mobile

The two blog posts mentioned above [1] cover more or less my thought process on the matter, so I’ll refer them to you if you’re interested in the innards of it all, but they left out one detail that has its importance on mobile: theme-color.

The theme-color value for the name attribute of the <meta> element indicates a suggested color that user agents should use to customize the display of the page or of the surrounding user interface. If specified, the content attribute must contain a valid CSS <color>.
Source: MDN

The head section contained the theme-color element along with the prefer-color-scheme media query for both themes.

<meta name="theme-color" content="#ffc036" media="(prefers-color-scheme: light)" />
<meta name="theme-color" content="#4a525a" media="(prefers-color-scheme: dark)" />

But it turns out that if your system preferences are set to ‘light’ and you switch to ‘dark’ via the theme toggle, the surrounding user interface remains in ‘light’ (as specified above).

Screenshot showing the user interface with the light theme
Light theme all around
Screenshot showing the user interface with the incorrect colour
The user interface remains yellow after switching to dark mode
Screenshot showing the user interface with the proper colour
All is dark now with the addition of the `theme-color` element

This can be fixed by adding a plain theme-color value with no media query attribute that can be changed via the theme toggle script.

<meta name="theme-color" content="#ffc036" />
<meta name="theme-color" content="#ffc036" media="(prefers-color-scheme: light)" />
<meta name="theme-color" content="#4a525a" media="(prefers-color-scheme: dark)" />

The toggle switch script is a little less elegant now as I had to hard code in the colour values, instead of just relying on a html data attribute value (light | dark).

I considered reading the prefer-color-theme media queries values, but they aren’t loaded yet when the script runs. A way around could be to default to the light value and store the current colour value alongside the visitor’s preferences in localStorage. I need to give it a try.

The theme can be fully changed via the system settings or by clicking on the toggle switch, whatever the initial settings are.

Reset switch

What is still missing is a way to reset or revert to ‘Automatic’. As soon as you click on the toggle switch, the setting is saved to localStorage and will prevail over the system setting.

Screenshot of macOS Appereance System Preferences

This could be an issue if the latter is set to ‘Automatic’, but there is no way of determining for sure if the visitor has set its system preferences to ‘Automatic’, but prefers reading this website in dark (or light) mode - or clicked to try the themes, but prefers the website honouring the system preferences. The toggle would require an ‘auto’ mode, but it wouldn’t be a toggle anymore, it would be a dropdown menu.

For the time being, I added a (hard to find) link in the footer area to delete the localStorage value basically just for me.

Screenshot of the fotter of the website with an icon representing a half-darken circle

The bottom icon only shows up if a localStorage theme key exists, and deletes it when activated.

I’m contemplating the idea of extending the toggle to a 3 position switch:

[ light → dark → auto ]

It wouldn’t be discoverable, and wouldn’t function as 2 state toggle, but could do the job, while being more elegant than a dropdown menu, which is the obvious answer in this case. Some judicious microcopy would b required.

Anyway, for the time being, I’m enjoying a modified version of the beautiful toggle switch component designed and developed by Adam Argyle, I shamelessly borrowed it from his blog post.

For now, I’m off to the Montreux Jazz Festival to enjoy the fabulous Raye live 💜 Enjoy your summer ☀️

Posted a response ? — Webmention it

This site uses webmentions. If you've posted a response and need to manually notify me, you can enter the URL of your response below.

Want more ? — prev/next entries