As you know dark mode is pretty much taken for granted these days and adding one is pretty straightforward. My usual approach is to default on the user prefer color scheme and then apply an .inverted class on the main document to flip the color scheme.
All that is not an issue. The problem is that I store the user preference on a cookie and cookies don’t play nicely with cached content.
So the usual solution to that problem is to apply the class using JS but that has the annoying issue of showing for a split second the default color scheme before the script run and applies the class.
So my question is, is there an alternative/better solution to deal with this issue?
When I have to include a dark mode my usual approach looks kinda like this:
I usually have colors stored in css variables like this and then I have a preferred color scheme media to set the base colors for people who want the dark scheme by default
:root
--bg : white
@media (prefers-color-scheme : dark)
--bg : black
But then I usually have a toggle on the front-end because sometime people who have dark mode by default want to navigate a specific site using light scheme and vice versa.
And I do that by applying an inverted class on the html and swap the colors around like this
html.inverted
--bg : black
@media (prefers-color-scheme : dark)
--bg : white
This way I respect the user’s default preference but I also offer the possibility to use the opposite color scheme
Reading “.inverted” and prefers-color-scheme with overwriting --bg somehow bamboozles me totally.
I think this approach works fine, but it also looks like double maintaining CSS variables with back and forth overwriting. Just found a nice logic for maintaining a hierarchy by keeping the state inside a data attribute that looks like the following:
// Light Theme (Default / Forced)
[data-theme="light"],
:root:not([data-theme="dark"])
--bg: white
// Dark Theme (Auto)
@media (prefers-color-scheme: dark)
:root:not([data-theme="light"])
--bg: black
// Dark Theme (Forced)
[data-theme="dark"]
--bg: black
Here we have a light theme on default, overwrite when the user set dark mode on, and force themes by attribute (that can be changed via JS to allow to switch themes.) Bonus for me: no .inverted class.
Yeah this could also work. There probably are a bunch of ways to handle this situation. Honestly, maintaining the two sets of variables is not that big of a deal for me. It’s something I set up once at the beginning of the project and takes maybe a couple of minutes max.
That said, I’d love for browsers to have a per-site setting of what I want my preferred color scheme to be.