How Does Theme / Font Switching Work?

In an ideal world, the user doesn't have to toggle things on a site, because everything about their preferences can be known in advance. We're not there yet, but the strategy is obey what we can get correct automatically, and provide controls as fallback.

Some settings (like prefers dyslexic font) don't quite exist yet in the form prefers-color-scheme does, and some don't even have a universal designation for what icon should enable them.

So we just try to do our best.

What are data-theme and data-font?

At the right of the top navigation bar, there are two switches, one that toggles light and dark mode, and another that toggles between the default system font and a user-preferred font, which in this case is OpenDyslexic.

In src/_includes/js/main.js there are events that run when the buttons are clicked, which toggles the theme or the font. The preference is stored in local storage, and synchronized when the document loads. There's also a dictionary to translate system to the default Infima font family, and user to OpenDyslexic, in case you want to change the font it toggles.

Working With Light / Dark Mode In CSS

We try to go by prefers-color-scheme, if it's available, so we know if they want a darker theme by default. Selecting one or the other stores their preference in local storage.

As you design with both themes in mind, you'll find that you need to adjust how something looks but only in a specific mode. In order to scope that, use data-theme.

Here's an example from the tags in this theme:

.post-tag:hover {
  background-color: var(--ifm-color-secondary);
  color: var(--ifm-color-black);
  text-decoration: none;
}

[data-theme="dark"] {
  .post-tag:hover {
    border: 1px solid var(--ifm-color-gray-700);
    background-color: var(--ifm-color-info);
  }
}

You can find a list of default color variables for both light and dark mode in src/_includes/css/theme-variables.css.

Adjusting CSS Automatically For Font Changes

Much like dark mode, larger fonts with thicker borders tend to wreak unanticipated havoc. Sometimes you want a slightly larger min-height or perhaps less padding. This is possible in a similar way to scoping the theme, except we're going by the font value.

Here's an example from the front page of this site where the cards line up under the hero:

/* Example of adapting design to a font-switch */
.homepage_card {
  min-height: 275px;
}

[data-font="user"] {
  .homepage_card {
    min-height: 365px;
  }
}

Otherwise, the page would not transform well when switched.