How to Add a Dark Mode Toggle to a Jekyll Site

Note: most of the information here is already outdated. Check out my newer guide to dark mode.

Dark theme, night mode or whatever you want to call is all the rage for websites. Rightly so, staring at an overly illuminated screen all day or trying to reduce your evening light exposure are worthy goals.

If you have a static site — my blog is built with Jekyll, but this is same concept if you use Hugo or Gatsby, you can’t use the server to change the CSS from backend to hop back and forth between light and dark modes.

Image for post
Image for post
Photo by Callum Shaw on Unsplash

There’s three ways to change CSS on the front end so that whoever is reading a site will still in the color mode they selected:

  1. Cookies. A no go for me because the EU cookie thing is annoying.
  2. URL Parameters. I got this to work, but URLs are clunky looking and this sometimes breaks navigation to different parts of the same page.
  3. Local Storage. The clear winner: unnoticeable to readers and works well with the new in CSS.

The concept

To be clear I wanted a switch that allows readers to select whichever color mode they want, and that mode needs to not revert to the default when someone moves around the site. Furthermore, I didn’t want a flash of either black or white when moving between pages.

This meant that I needed a button that triggered a script change the pages CSS and add local storage telling future page loads which color scheme to use.

To make it even more complicated, I wanted the default to be day mode unless someone’s system preferences were set to dark mode. Thus I’d need some frontend JavaScript to figure out what the color scheme of the initial page load and save the preference to local storage.

The CSS

On my first attempt, I used two CSS files and swapped them out based on the preferred color scheme. This caused flashes of white or black when moving between pages in Firefox and Chrome. This is a common shortcoming of a lot of sites with dark mode toggles.

The solution is simple enough: use a single CSS file with variables. Here’s what my CSS looks like:

By default, the light mode variables will be set and that’s how the site will load. To get dark mode to load, we have to use JavaScript to change HTML data attribute to “dark”. Going back to light mode is same in reverse, changing the HTML data attribute to “light”.

Of course, when you specify the colors for various elements in your CSS use the variables and not absolute values!

The last bit of CSS is adding a way to detect whether a site visiter prefers dark mode:

The button

I put a simple button at the top of each page on my site:

The JavaScript

At the very top of the page, I inserted a tiny script to check if dark mode has already been entered into local storage. If you run this at the end of the page, you’ll get a white flash when navigating between posts.

At the end of each page I inserted this script:

This script checks if a visitor prefers dark mode, and if so applies dark mode and notes it in local storage. If someone clicks the button, the mode gets changed and local storage updated accordingly. Additionally, the text of the button is updated to match the current color mode.

The result

Like magic, you now have a dark mode toggle that works on a static site. You can have fun with this and add toggles for other things like sans-serif or serif fonts.

You can check out the button yourself on the original post.

Written by

UX writer @Wix

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store