By Tess |
February 19, 2024
*according to Tess
I just implemented the light/dark toggle for BlogPlat, which runs this blog. there's a suprising amount of subtle complexity in this simple feature, so I'm writing this in case it's useful to anyone.
modern browsers expose the browser/system setting via window
. we want to respect this by default.
we also want to allow the user to toggle dark mode on our site in particular. we could expose three modes (light
, dark
and respect system settings
), but that might be confusing to users. instead, we will have a button that always toggles between light and dark. when the user requested setting is the same as the system default, the system default is used (and the displayed theme changes if the system default changes later). if the user selects the other mode than that mode is forced (and system default changing does not effect it).
we save the user's preference (light
, dark
or default
) in local storage so it persists and applies to all pages on our site.
we listen to changes of both system preference and local storage, so OS/browser settings changes and changes from other open pages apply instantly.
we add the light-mode
class to the body
element when light mode is active, and remove it when dark mode is active. we then use CSS variables to change colors on the page based on the class:
:root {
--text: white;
--background: black;
}
.light-mode {
--text: black;
--background: white;
}
body {
color: var(--text);
background: var(--background);
}
we don't want it to momentarily flash the wrong color on load, so our script uses addEventListener
instead of addEventListener
.
you can find the JavaScript file that implements all this here. it can be included in <
. you call onLightModeToggled
when the user toggles the mode (typically in the onclick
of the toggle button) and isLightModeEffective
if you need to know the current state (returns true
for light and false
for dark).