Making a dark / light mode theme switcher

by Ryan Yang

Note: This is not a complete guide on dark mode, but rather a quickstart for new developers to get a theme setup up and running in a small codebase. For a more in-depth analysis regarding dark modes, you can check out this amazing article written by Ryan Feigenbaum.

Intro

Intro

For people who have used their phones/computer in the dark, dark mode is one of the most coveted features around. Before we dive into how we can create a dark mode and toggle it, let's first take a look at what dark mode is. Dark mode is a design concept that utilizes light colors (usually white or pastel-like colors) for text and icons contrasted with a dark background, as opposed to the usual dark colored text on a light background (like a book or print newspaper).

Why have a dark mode?

Why have a dark mode?

Aside from dark mode looking cooler than light mode (personal and subjective preference, of course), dark mode can reduce eyestrain in low-light conditions. Ever surf the web on your phone at night and you visit a page that completely blinds you with white light?

You can see the end results below to get a feel for what dark mode looks like in case you're unfamiliar but without further ado, let's go ahead and implement it

Implementing dark mode

Implementing dark mode

Starting code

Starting code

Imagine we have the following website without dark mode (a.k.a. light mode) that we want to add dark mode to:

File Structure

making-a-theme-switcher
index.html
styles.css
script.js

index.html

And we style it like this (light mode):

style.css

script.js

When we test this code in the browser, we get something that looks like this:

Light mode look

Dark mode styles

Dark mode styles

In this simple example, to convert our design into dark mode, we only need to swap a couple CSS styles. More specifically, we will be toggling the background-color and color properties only. Below are the values we will be swapping to but keep in mind that we can toggle ANY css property we want and are not just limited to color styles. (The /* ... */ is a CSS comment which denotes that the content is left unchanged and not listed again to keep things short)

style.css

Swapping these styles will result in something that looks like this:

Dark Mode Image

CSS Variables

CSS Variables

There are a couple ways to implement a dark mode but the way I'll be showing you is with CSS variables. So, how does it work?

CSS variables are essentially placeholders for values and you can update them with Javascript. They operate like variables in Javascript or any other programming language and when they get changed, the webpage will immediately respond and apply the new CSS styles, rerendering the webpage.

Applying CSS variables to our code

Applying CSS variables to our code

Since there are 3 things we want to toggle, we will only use 3 variables.

Elements that will change stylesLight Mode (color/hex code)Dark Mode (color/hex code)
Background color of pagewhite / #FFFFFF*dark grey / #151515
Background color of card itemwhite / #FFFFFF*dark blue-grey / #15171A
Color of textblack / #000000white / #FFFFFF

* - description of color, not actual CSS value

Declaring CSS Variables

Declaring CSS Variables

First, we need to initialize the variables and give them a default value. We can define global variables in something called the root, which is a top-level CSS selector, denoted below:

style.css

Ok. What the heck did we just do? Well, the general CSS syntax is still the same where we have our selector and a bunch of [property]: [value];'s for the selector. Our selector is :root, which is a level above html and so that allows us to use these variables from anywhere in our CSS code. (If you're comfortable with programming concepts, you can think of these as global variables.)

What might not be familiar, however, are the properties for the selector. The -- in front of the property lets our CSS know that we are declaring values for a CSS variable, not a CSS style. Everything after the -- and before the : is our variable name. CSS variables are case sensitive and we use, by convention, a single dash, -, if our variable name has multiple words.

Using CSS Variables

Using CSS Variables

Now that we initialized the CSS variables in our :root, we can use them where we need. Our CSS page will eventually look something like this:

style.css

Notice, we simply replaced the value of the CSS style with the variable name. We use var() to let CSS know that the value we are applying is going to be a CSS variable, rather than an actual, hardcoded value.

Working with Javascript

Working with Javascript

Dynamically changing our CSS Variables

Dynamically changing our CSS Variables

Let's recap what we've done so far. Instead of having hardcoded values in our CSS styles, we've now attached CSS variables to our styles and defined the default values in our :root selector. However, none of this gives us dark mode, nor does it allow us to toggle our styles yet.

The next question is, how do we now utilize our CSS variables and change them on the fly? Take a look:

script.js

The code above simply creates a function named changeToDarkMode and will target the :root styles (with document.documentElement.style) and individually set every variable to a new value. In this case, it will set the CSS variables we defined earlier that represent background colors to something darker and the text color to white.

We can, say, attach this function to a button in our HTML and when we click it, it will toggle our website into dark mode.

index.html

style.css

script.js

This results in a webpage with a button that can toggle our page into dark mode like so:

Dark mode toggle demo

Toggling

Toggling

Great! So we can turn our website into dark mode with the press of a button... but how do we turn back if we like it better in light mode? This is going to take some engineering on our part.

First, we're going to need another variable - only this time it'll be in javascript - that can keep track of what mode we are in so we know what mode we'll be toggling into.

script.js

Saving and loading themes

Saving and loading themes

When our user toggles a theme and leaves the website, we should keep track of their preference so that the next time they visit the site, they won't have to toggle again. Here, we can use the built in LocalStorage object to help us save data in the browser in between sessions (persistent storage).

script.js

Finishing touches

Finishing touches

Personally, I find the sudden swap of CSS styles too abrupt of a change for my eyes. I would much rather prefer a slow, animated transition and thankfully, CSS has a powerful animation style called CSS Transitions. What transition allows us to do is specify whether or not the browser should compute animations for us when certain styles are changed. We set the animation style, duration, delay, and even speed and the browser will automatically render it whenever it that style gets changed. It's a lil' confusing so let's take a look at how it works in action:

style.css

Which results in this:

Final Demo

Just the code

Just the code

You can find the code for a running example here: https://github.com/ryqndev/learn-ryqn-dev/tree/content-update/src/content/making-a-theme-switcher/docs

How do I run this code? Go ahead and click that link above ^ and download those 3 files (index.html, style.css, and script.js) and open up index.html in the browser. (You can do this by right clicking the file icon and selecting "Open with..." and selecting your preferred browser).