Daniel Pietzsch

Personal blog. Mostly photos.

Dark mode

This blog now has an option to enable a “dark mode”. Meaning, you can see everything on a dark background. Just click or tap the checkbox next to the little moon (🌙) in the top right corner. Your browser will remember the setting the next time you visit – which I hope you will.

The dark background is much gentler on the eyes when looking at your screen in a dark surrounding and generally nicer for looking at photos. And since that’s the content I post most frequently, I might even make this “dark mode” the default in the future. But for now, it’s an option.

The technical background

I’ve had this separate “dark mode” for a while now. But since it had no user interface (UI) on this site, it could only be discovered and enabled, when the browser recognized alternate stylesheets and itself offered a UI to switch between them. Of the major browsers, I think that’s only Firefox’ desktop version – at least on a Mac. And even then I think most folks don’t know about – or use – this.

Searching online for some help, I found this ancient article by Paul Snowden on the A List Apart website from 2001. While dated, it still was describing pretty much what I wanted: a little script to switch between alternate stylesheets of a website (as opposed to – for example – toggling class names on the <body> tag or something similar). I couldn’t and didn’t want to use the author’s script as is. But the article gave me the hint that <link> and <style> tags have a disabled attribute which I can use to enable or disable them. So off I went to write a little script that does these four things:

  1. Make the UI visible – in this case a checkbox plus label – to toggle the stylesheets (because in case JavaScript is disabled, there’s no need to render the UI, since you couldn’t use it anyway).
  2. When the checkbox is toggled, loop through all relevant <link> and <style> tags and enable or disable styles accordingly to the current setting.
  3. Store the name of the enabled stylesheet in the browser’s localStorage to be able to retrieve the preference for future visits (and further navigation).
  4. Read the preference from localStorage on page load to enable the visitor’s preferred style.

Here’s the whole script:

function switchStyles(enabledStyleTitle, disabledStyleTitle) {
  var links  = document.getElementsByTagName("link")
  var styles = document.getElementsByTagName("style")

  for (var i = 0; i < styles.length; i++) {
    if      (styles[i].getAttribute("title") == disabledStyleTitle) { styles[i].disabled = true }
    else if (styles[i].getAttribute("title") == enabledStyleTitle)  { styles[i].disabled = false }
  }

  for(var i = 0; i < links.length; i++) {
    if (links[i].getAttribute("rel").indexOf("style") != -1 && links[i].getAttribute("title") == disabledStyleTitle) { links[i].disabled = true }
    // I don't exactly know why I seem to need to "double-toggle" this here. But on WebKit-based browsers, it wouldn't apply the appropriate style on first page load. And this seems to do the trick.
    else if (links[i].getAttribute("rel").indexOf("style") != -1 && links[i].getAttribute("title") == enabledStyleTitle)  { links[i].disabled = false; links[i].disabled = true; links[i].disabled = false; }
  }

  localStorage.preferredStyle = enabledStyleTitle
}

function switchStylesBasedOnChecked() {
  if (styleSwitchCheckbox.checked) {
    switchStyles("Dark", "Light (default)")
  } else {
    switchStyles("Light (default)", "Dark")
  }
}

// START HERE
var styleSwitchCheckbox = document.getElementById("style-switch")
 styleSwitchCheckbox.parentElement.style.visibility = 'visible'

// simply "check" the checkbox when the user's stored preference was "Dark"
if (localStorage.preferredStyle == "Dark") { styleSwitchCheckbox.checked = true }

// On page load, making sure the correct setting is applied
switchStylesBasedOnChecked()

// Whenever the checkbox changes, switch styles again
styleSwitchCheckbox.addEventListener('change', function(event) { switchStylesBasedOnChecked() })

Feel free to use this script yourself – unmodified or modified.

I also like to high-five the person or team who was responsible for the localStorage API. So straightforward, I almost couldn’t believe it.