Create a Dark Mode for your website

Jake McCambley
Bootcamp
Published in
11 min readJul 5, 2021

--

Dark Mode is popular, and for good reason. Does it require less energy? Only on some devices. Does it reduce eyestrain? It actually doesn’t. Does it look damn good? Absolutely.

The undertaking of creating a Dark Mode for your personal website is a pursuit that shouldn’t just follow a trend, it should augment your user experience and align with your brand.

Demonstration of Dark Mode
Photo by Sten Ritterfeld on Unsplash

Configuring a Dark Mode is quite simple. This walkthrough will take you through one method developers can use to design and code one on their own website. This walkthrough will use HTML5, CSS3, and Vanilla JS, no CSS extensions or Javascript Libraries.

To get a preview of what you’ll be building, take a look below at a project that applies this method. Pay special attention to what colors are used, how the toggle is built, and what the script is actually doing. If you inspect the page, look at how the DOM adjusts when the toggle is active. All these things are explained in detail below, but looking for these things now will prime your understanding of things down the road.

Here are the steps:

  1. Consolidate your color scheme
  2. Create a Dark Mode color scheme
  3. Create a custom toggle button
  4. Switch the theme when the toggle is checked
  5. Make sure user settings are saved

Consolidate your Color Scheme

To get started, compile all the colors used in your project into a collection of Custom Properties attached to the root class. Instead of declaring explicit color values at each class used throughout your stylesheets, you’ll collect them into a small list of CSS variables all located in one accessible location.

Instead of the following code:

CSS code without using custom properties
No CSS Variables

Your code will look something like this:

CSS code with custom properties
Color With CSS Variables

With more lines of code and some unfamiliar syntax, it might be difficult to see what was gained in this step.

Readability — The color palette used on your page is no longer scattered across multiple classes and, potentially, multiple stylesheets. Additionally, there’s no longer any need to remember what each hex code or other color value is supposed to represent. With descriptive variable names it will be easier for you or another developer to read through this code and understand what the design intention was at the time of writing.

Maintainability — If you chose to make changes to you pallete sometime down the line, there’s no longer any need to sift through lines and lines of code to find each instance of #a1a1a1. Now changing the color pallete only requires a brief visit to the root class. If the value of --main-content-color is changed there, it will adjust accordingly for each class where that variable is referenced. You’ll see how that become relevant to a Dark Mode theme later in this walkthrough.

Note: CSS Variables are not supported in Internet Explorer. If you so chose, you can work around this by placing backup values each time a CSS variable is called.

Create a Dark Mode Color Scheme

There are many fantastic guides detailing how to create Dark Theme palette for a page that aligns with your brand and maintains a high quality user experience once enabled.

To summarize a few key points:

  1. Don’t simply invert your Light Theme — Just because your light background is white doesn’t mean your dark background needs to be black. It can be blue, grey, red etc. Same goes for your other colors and components. What’s most important is that it looks good, is legible, and aligns with your brand.
  2. Avoid pure black and pure white — Picture the last time you used a website with Dark Mode enabled. Chances are, the background was slightly lighter than black and the text was slightly darker than white. Github and Stack Overflow are great examples of this. Those high contrast colors a slightly uncomfortable to look at, so opt for something more palatable.
  3. Maintain accessibility across themes — It’s important that everyone who visits your page can read your text. If you choose off-black as a background and off-white as your primary text, as per the direction above, you might lose something by ways of legibility. Pick your colors such that they conform to minimum contrast standards. An easy way to ensure that is to use a tool like Accessible Colors.

For the purposes of this exercise, I would encourage you to use a tool like Coolors to find a color palette that works for you. Import yout Light Theme, tinker around, and move on. Don’t worry if it’s not perfect. Now that you’ve got your colors consolidated in a single class, it will be easy to adjust colors if you feel the need to later on.

Once you’ve got your colors picked out, the next step is to create a modifier class in which you’ll store your Dark Theme custom properties. Since you can’t modify the :root class, you’ll need to move the Light Theme created in the above step to an appropriately named class. To keep things simple, move your Light Theme palette to a class named light and your Dark Theme palette to a class named dark. These classes will be applied to the wrapping <body> tag and from the there the colors will be inherited by descendent elements where they’re needed.

If before your :root looked something like this (this sample is taken from this project):

CSS code displaying a root class with CSS variables
:root class prior to modification

Make sure your code has been adjusted to look like the following:

CSS code displaying a two root modifier classes with CSS variables

Before moving on, apply your light class to your <body> tag to ensure that the colors remain in your project. If you want to test out the appearance of your dark class, simply apply that class to the <body> tag instead. Once you’re ready to move on, replace the light class to the <body> tag and leave your dark class off to the side. You’ll come back to that later.

Create a Custom Toggle Button

The goal is to eventually create a method for replacing the light class with the dark class without having to hand code the class in yourself. In the same way you need a switch to turn a light on and off, you’ll need a toggle to control your theme.

There are a number of different ways to go about constructing a toggle. The method described below is certainly not the only way. W3 describes a simple functionality in which the click of a button runs a simple toggle function that adds or removes the dark-mode class from the <body> element.

The method used in the example displayed earlier is very similar. Here, you’ll use a checkbox input as the primary toggle. When the checkbox is checked, Dark Mode is enabled. When the checkbox is unchecked, Light Mode is enabled. The reason a checkbox is used instead of a simple button will become apparent in the last section of this post, when storing the state of the toggle is discussed. The purpose of this section is to discuss how the toggle is constructed.

Building the toggle — The markup for the toggle is fairly simple. Create a toggle container containing a checkbox input and a label.

HTML markup for a toggle display
View all the source code here

At this point, the input is on your page but there’s nothing tying it together with the rest of the project. The checkbox input appears as a default input according to your browser. Of course, if this is enough for your page, moving on to the next steps would certainly be a fine thing to do, but it could be worth taking the extra time to style the toggle inline with the rest of your page.

Styling the toggle —Notice that when you click on an input’s label, the input itself is toggled. That’s what will allow the following process to work. In short, styling the toggle as it appears in the example above requires you to style the input as a button, and then hide the checkbox behind it.

Start by remove the input from the flow of the page and making it invisible. applying the following CSS to the toggle container and checkbox:

CSS code for the toggle
Again, the source code can be found here

At this point, with the markup created in the previous step, you should only see the input label and nothing else.

Now, style the label to appear as a button, an element with a background, rounded corners, centered content, a pointer cursor, and some nice transition effects.

CSS code for the toggle
Toggle label styling

To make it clear to your users what the button will do, you might want to change the label text to Enable Dark Mode. Better yet, replace the text all together with an SVG icon. You can find a fantastic collection of icons here. Search “moon” and “sun” to find the icons used in the example above. Adjust your markup accordingly.

HTML markup for a toggle using an SVG icon
Markup updated to display SVG icon

Later, you’ll learn how to change the src and alt of the icon when the input is changed. The color of each icon can be changed by editing the code of the SVG itself. Find the fill property and hand code in the color you want to display when the icon appears.

You’ve successfully created a toggle with which you can bring some functionality to the page. To recap: the checkbox input has been hidden behind a restyled label that will act as the button with which you toggle the theme of your page.

Switch Themes with the Click of a Button

Now that the toggle is built, it’s time to make it do something. This is where Javascript will come into play. What you’ll do is write a script that listens for change in the toggle’s input. When the input changes, replace the existing theme class with the new theme class and change the content of the button accordingly. This will look something like this:

Javascript code for the toggle
Full script can be found here

Inside the toggleTheme() function, the following logic will ensue:

  1. If the toggle is checked, replace the light class with the dark class on the page element. If the toggle is unchecked, replace the dark class with the light class.
  2. After the class is successfully replaced, adjust the call to action content of the button accordingly. In the example, if the light class is present, the source of the img tag will be the moon icon, inviting the user to enable Dark Mode. If the dark class is present, the source of the img tag will be a sun, inviting the user to enable Light Mode.

Using a few if…else statements to implement the above logic, the toggleTheme() function can be expanded to look like this:

Javascript code for the toggle written out in full
toggleTheme() expanded

In order to make sure that your function only does one thing, you can extract each if…else statement into its own function. This should look something like this:

Toggle javascript code refactored so that each function does one thing
Each function does one thing

The project is nearly complete. You’ve consolidated your default colors into a theme, created a Dark Mode theme, then built a button toggle that allows a user to switch between the two themes. There’s only one step left.

Save Settings to Local Storage

At this point, everything seems to be working. The only problem however, is that refreshing the page will reset the theme to the default setting. This prevents any continuity in the user experience. As the user navigates through pages within your website, or clicks your logo to return to your landing page, they might be surprised to find a setting they actively chose to avoid greeting them upon their arrival. Ideally this is to be avoided.

Fortunately, the use of the window’s localStorage property provides access to a storage object that will retain data across independent browser sessions. Better yet, localStorage will behave the same for most users that access your website, regardless of their browser.

The localStorage object has four primary methods, setItem(key, value), getitem(key), removeItem(key), andclear(). For the purposes of this walkthrough, pay closer attention to the first two methods. Take a look at how they work in the following example:

Localstorage code demonstration
localStorage demonstration

Notice in the above demonstration how the data stored in the object remains after the page refresh. This will be the most relevant feature of the localStorage property with regards to the Dark Mode toggle. Instead of storing a username, however, you’ll be storing the state of the checkbox. That data will then be used by the browser to determine what class to apply to the <body>.

Here’s how it will work:

Javascript code for Localstorage functionality

There’s a few things going on above:

  1. Setting the toggle’s checkbox state — Read the localStorage object. If there has already been a key value pair stored from previous toggles, set the toggle according to that key value pair
  2. Toggling the theme — Update the class attached to <body> according to the current state of the checkbox
  3. Updating the localStorage object — The new added functionality inside toggleTheme() stores the updated state of the toggle’s checkbox inside the localStorage object

When the page initially loads 1, 2, and 3 will be completed right away. Each time the toggle is activated, steps 2 and 3 will run. If, on the initial page load, there is nothing stored in localStorage, the checkbox will remain checked or unchecked as defined by the markup.

Here’s how the functions will look built out:

Localstorage code written out in full
Save theme settings with localStorage

Check to see that everything is working by activating the toggle then refreshing the page. The theme should now remain as you left it during the previous session. If you’d like to see the full script written out, you can find that here.

If everything is working as it should, congratulations, you now have a fully functional Dark Mode on your website!

Conclusion

At long last the process is complete. During this process you’ve successfully:

  1. Consolidated your color scheme — Moved color values into one class using custom CSS properties
  2. Created a Dark Mode color scheme — Created a secondary color palette to compliment the consolidated class in the previous step. Tools like coolors make this easy
  3. Created a custom toggle button — Customized a checkbox input to appear as a button
  4. Switched the theme when the toggle is checked — Built a few functions, each doing one thing, that all come together to change the theme class attached to <body> when the toggle is activated
  5. Made sure user settings are saved — Utilized the window’s localStorage property to access a storage object in order to save user settings across independent sessions

And with that your Dark Mode is complete. You’ve successfully improved upon the initial design and functionality of your website in order to cater to modern demands and enhance your user experience.

To see this walkthrough in action, check out this demonstration. Find the repository for this project here.

Cheers! 🍻

--

--

Learning to code by teaching others — Living at the cross section of tech, music, and the outdoors — Currently studying Web Development at Practicum by Yandex.