Qubyte Codes

Dark mode

Published

That's right! After more than a year of talking about adding a dark mode I finally did it. The wider support for prefers-color-scheme is what pushed me over the edge. I'm also a slave to fashion.

Initially I wanted to create a sort of dark-mode-battenberg theme, but after a while using dark mode site I came to realise that my favourites are the ones which use as much black as possible. It's becoming more common to see OLED screens in the wild, and these use less energy for black pixels since OLED pixels are self illuminating. I settled on using black for the background, and borrowing my light mode background colour for text and borders.

The additions to the CSS aren't too dramatic, but I learnt a few things along the way

@media (prefers-color-scheme: dark) {
  :root {
    --background-color-main: #000;
    --background-color-alt: #000;
    --standout-color-main: hsl(
      var(--base-background-hue),
      var(--base-background-sat),
      var(--base-background-lum)
    );
    --standout-color-alt: hsl(
      calc(var(--base-background-hue) - 30),
      var(--base-background-sat),
      var(--base-background-lum)
    );
  }

  img:not([src*=".svg"]) {
    filter: brightness(.8) contrast(1.2);
  }

  pre, input, button {
    background-color: #000;
  }

  code {
    filter: invert();
  }
}

body > header {
  z-index: 1; /* works around stacking context issue introduced by filters */
}

The media query applies the content only when the OS is in dark mode and the browser supports the media query. The :root swaps the background colors to standout colours, and makes the background black.

Non-SVG images have their brightness and contrast adjusted with a filter. I borrowed a dark mode filter from Melanie Richards as suggested by Jeremy Keith.

Code listings are more difficult. I plan to do a bit more on these later, but for now, since the regular code is on a white background, I give dark mode code containers a black background and apply an invert filter to the code. I also set the background color of inputs and buttons to black to fit.

Finally, the filters had an unintended side effect. Filters place the elements they apply to above positioned elements in the stacking context, which led to images and code listings scrolling above the nav bar (which is part of a sticky positioned header). To address this issue I resorted to using z-index. While the rule of thumb seems to be to avoid use of z-index, I believe it's appropriate in this case.