22 Mar 2020   siteupdate  0   web-design, css, devnotes, darkmode

2019 was the year of the dark (mode). While this site has had its own dark mode since 2018, it's about time I give a few things a redo on this site.

Those familiar with this site and myself know of my obsession with dark mode: I have a dark background on my terminal, I install dark usercss for sites I frequent, I make dark-mode-first PDFs, and I configured by PDF viewer to recolor documents to be dark by default. For 2019 to be the year of dark mode, I felt like I was truly blessed by whatever omnipotent deity there is.

With 2019 now in the past, I figured it’s probably a good time to revisit how I’ve did my color scheme swapping. I recognize that it wasn’t a good idea to load all of my styles in one file, have two completely separate files with a lot of similarities, and swap the two “big” files while changing themes. There were two reasons why I employed that decision;

• CSS variables was not widely used at the time; and
• CSS preprocessors do not work very well with CSS variables.

## Taking advantage of CSS Variables

The second situation of the above two has not improved, seeing that it’s not really a priority. However, CSS variables is now more widely used; sitting at 94.68% coverage. I remember seeing it being around the 80s in 2018, but I could be wrong. While I understand that the calculated coverage is a rough estimation, looking at the chart on caniuse.com, I think it’s quite fair for me to fully adopt it.

What this entails is that I can put all the variables into the :root pseudo-class, wrap it with the prefers-color-scheme media query, and call it a day. At the time of writing, the browser coverage of prefers-color-scheme is at 80.85%. But the workaround is simple; simply have a fallback to default values.

But wait, what about good ol’ on-the-site color scheme swapping? Unfortunately, it doesn’t go very well with prefers-color-scheme. Say if we have the following CSS declarations in our light and dark color CSS files.

:root {
/* "swappable" colorscheme goes here */
}

@media (prefers-color-scheme: light) {
:root {
/* light colorscheme goes here */
}
}

@media (prefers-color-scheme: dark) {
:root {
/* dark colorscheme goes here */
}
}


Then we’re giving priority to the user’s preference, and no swapping of the color schemes would properly work. If we do it the following way:

@media (prefers-color-scheme: light) {
:root {
/* light colorscheme goes here */
}
}

@media (prefers-color-scheme: dark) {
:root {
/* dark colorscheme goes here */
}
}

:root {
/* "swappable" colorscheme goes here */
}


then the media queries might as well not exist. Bummer!

However, what we can do is to go forth with the first method, and then plug in a new :root with the on-the-site chosen color scheme after the media queries.

<link rel="stylesheet" href="base-with-prefers-color-scheme.css">
<!-- the following are injected with JS -->
<!-- if user picks dark color scheme -->
<!-- if user picks light color scheme -->


I think that’s an acceptable approach.

## Time-aware color scheme

Those who have been on this site for a while knows that it uses the different color schemes (light and dark) at different times, provided that you have not switched between the color scheme in the session before. Particularly, there is a mechanism (read: JavaScript) in place to automatically put you in dark mode between 5pm to 8am the next day, while for the rest of the time, you’ll be in light mode by default.

function timeSensitive() {
const curHour = new Date().getHours();
if (curHour > 16 || curHour < 8) darkTheme();
else lightTheme();
}

if (typeof(Storage) !== "undefined") {
switch (sessionStorage.theme) {
case "light":
lightTheme();
break;
case "dark":
darkTheme();
break;
default:
timeSensitive();
}
} else {
timeSensitive();
}
}


The way we respect the user’s choice here is by keeping a key in sessionStorage At the time of writing, the compatibility coverage of sessionStorage as recorded on caniuse.com is 95.3%. when the user does make a choice with the color scheme toggler.

With devices themselves having the option to automatically switch between modes at specified times, or simply by checking for sunrise and sunset, I think it’s a good idea to sunset this feature and let prefers-color-scheme do its job. The user will always have the choice to change the site’s color scheme if they wish to, and that should remain at the discretion of the user, as we respect their preference from the prefers-color-scheme media query.

## Inherent problems

prefers-color-scheme is based on the preferences of the device, and changing this value on the device also changes the default appearances of textboxes, textareas, dropdowns, etc. Doing our own color scheme swap on the site would mean we’re trading off some UI inconsistencies on our site, like the following.

For me, that is a tradeoff that I’m willing to make. My opinion is that as web developers, we should have the option to style our input fields and whatnot. I understand that it is a tricky power to give, since that different browser vendors implement these components differently, and they even behave somewhat differently. Things get even more “complicated” on mobile, where your select input, say on iOS, doesn’t even show a dropdown, but uses their own rotary selector, which is a native feature. In some sense, we’re asking for the tools to reduce design inconsistencies, but it’s a never-ending rabbit hole to go down.

#### Final note

I think Sepia as a middle-ground color scheme is nice and should be implemented, in some form, as one of the options for the prefers-color-scheme media query. But that’s likely something for the slightly further future, where it will come to us naturally once we have figured out better ways to manage color schemes.

- Japorized -