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.
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:
- Cookies. A no go for me because the EU cookie thing is annoying.
- URL Parameters. I got this to work, but URLs are clunky looking and this sometimes breaks navigation to different parts of the same page.
- Local Storage. The clear winner: unnoticeable to readers and works well with the new
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.
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:
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:
I put a simple button at the top of each page on my site:
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.
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.