Adding support for Dark Mode to your site

More and more operating systems are offering their users a setting to see the User Interface in a dark mode. In 2018, we spent an average of 11 hours per day looking at a screen. In some cases, switching to dark mode helps to reduce eye strain, caused by looking at bright screens all day. It also helps preserve your device’s battery life.

Dark Mode

Dark Mode settings in macOS
Three Dark Mode settings in macOS (Light, Dark and Auto)

In most operating systems, Dark Mode can be manually toggled by the user. Also, there is usually a setting that allows dark mode to turn on automatically after sunset.

A lot of applications automatically adapt to the user’s dark mode settings. Google Chrome browser for instance, changes color scheme automatically based on my settings in macOS.

Unfortunately, this is not the case for many websites. They are still showing a white or very bright background, even when a user’s system is set to use a dark color scheme.

How to enable dark mode on your site

There are a few ways to add support for dark mode to your site. I’ll show you two ways to do it. The first method is an automatic dark color scheme based on the mode selected on the user’s device (light or dark mode). It’s great because it’s automatic and the user doesn’t need to manually turn it on. However, it may not work on all devices and/or browsers. The second method requires the website visitor to toggle dark mode manually by clicking a button.

CSS media query (automatic)

My favorite way to add dark mode to a site, is to use a CSS media query. The website will automatically detect the user’s color scheme settings from their device, and adapt accordingly. I’ve tested this on macOS (Chrome and Safari) and iOS (Safari).

The code fragment below shows how to give your site a black background color and white text color when dark mode is detected.

@media (prefers-color-scheme: dark) {
  body {
    background: #000;
    color: #fff;
  }
}

Obviously, for most sites just changing the background and text color will not be sufficient. Links may not have the right contrast ratio with the new background color or texts that would usually be dark grey should now be a lighter grey. In this site’s child theme, I have the following CSS to adapt to dark mode:

/* =Dark Mode
-------------------------------------------------------------- */
@media (prefers-color-scheme: dark) {
	body {
		background: #000;
		color: #fff;
	}
	.site-title a:link, .site-title a:visited {
	    color: #fff;
	}
	.social-navigation ul.social-links-menu li a {
		color: #fff;
	}
	.social-navigation ul.social-links-menu li a:hover {
		color: #fff;
	}
	.entry .entry-title a:hover {
    	color: #cacaca;
	}
	.entry-content a {
		color: #109ee2;
	}
	a.more-link {
		color: #109ee2;
	}
	.main-navigation .main-menu > li > a {
		color: #109ee2;
	}
}

The result can be seen below (click on the image for a larger view). If you’re using a device that supports dark mode, try switching between dark mode and the default (light) mode to see what happens.

The same page in light (default) and dark mode

One thing that is pretty amazing is that switching between dark and light mode doesn’t require the user to reload the page:

Manual toggle

Another approach to adding dark mode on your site is to offer users a toggle on your site. The benefit of this is that it will work on all devices and browsers, even if they do not natively support dark mode. The downside is that your site’s not automatically switching between light and dark mode, like the media query solution.

Body class

One of the ways to let users toggle between dark mode and “default” (light mode) is with a toggle button that triggers a CSS class to be added to the HTML <body>. First of all, make sure that each class has the relevant CSS to show your website in a dark or light color scheme. You can see an example below where the default body has a white (#FFF) background and black (#000) text. The “dark-mode” class has the opposite color scheme (black background, white text).

body {
  background-color: #fff;
  color: #000;
}
body.dark-mode {
  background-color: #000;
  color: #fff;
}

Within the page’s HTML, you should include a button that allows the user to toggle between default and dark mode. Make sure that the button has a “class” as well, for example darkmodetoggle:

<button class="darkmodetoggle">
Dark Mode On/Off
</button>

The below JavaScript will make sure that when a button with this class is clicked, the CSS class “dark-mode” is added to our <body>:

const btn = document.querySelector('.darkmodetoggle');

btn.addEventListener('click', function() {
  document.body.classList.toggle('dark-mode');  
})

Separate stylesheets

Of course you can also opt to use two style sheets on your site, one for the default color scheme (default-mode.css) and one for dark mode (dark-mode.css). You can see a simplified version of each stylesheet below.

/* default-mode.css 
************************/
body {
  background-color: #fff;
  color: #000;
}
/* dark-mode.css 
************************/
body {
  background-color: #000;
  color: #fff;
}

Next up, we’ll need to call in our default color scheme stylesheet into our web page. This is the default-mode.css stylesheet. The link to the stylesheet will need to have the “ID” (color-scheme in this example).

<head>
  <link id="color-scheme" href="default-mode.css" rel="stylesheet">
</head>

Next, we’ll need the JavaScript that triggers the stylesheet to “switch” between default and dark mode. As you can see, again we’re looking for a button with the “darkmodetoggle” class and the stylesheet link with the “color-scheme” ID.

const btn = document.querySelector(".darkmodetoggle");
const theme = document.querySelector("#color-scheme");

btn.addEventListener("click", function() {
  if (theme.getAttribute("href") == "default-mode.css") {
    theme.href = "dark-mode.css";
  } else {
    theme.href = "default-mode.css";
  }
});

Finally – like in the body class example – we’ll need to include the toggle button in our web page:

<button class="darkmodetoggle">
Dark Mode On/Off
</button>

Which method to use

My favorite approach – which I also used on this site – is the first, where the user does not need to toggle dark mode. I prefer to follow the preference set on their device as it is fully automated and also doesn’t require your site to remember the user’s preferences through a cookie or local storage.

The downside to using the media query method is that it’s not always supported on older devices and browsers.

Taking it further

There are some other considerations to make when adding a dark color scheme to your site.

Text color

One of them is the text color. White text (#FFF) on a black background (#000) may be too much of contrast. You may want to use a bit darker text, maintaining a contrast ratio that matches Web Accessibility requirements. I use this tool to check if the contrast is following the requirements.

Contrast ratio check
Use Contrast Checker to check if your text and background color have a good contrast ratio. You will see that you don’t need to use #FFF, but can use a grey text color.

Images

In dark mode, your images may also be perceived as “very bright” for users. Especially if everything around an image is dark, you may want to reduce the brightness a bit. You can do that very easily with CSS:

@media (prefers-color-scheme: dark) {
  img {
    filter: brightness(.8) contrast(1.2);
  }
}

The below picture shows the result. The left half of the picture is the original. The right half shows what the CSS above does to the image:

Left: the original picture.
Right: the picture with 80% brightness and 120% contrast.

Is it worth it?

After reading all this, you may wonder whether or not Dark Mode is worth the squeeze. For this (rather simple) site, it only required a few lines of code. I can imagine an extensive website with a shop and a lot of different elements could be a different story.

Adding support for dark mode, if done properly, can really improve the accessibility of your site and users will really appreciate it (even if they don’t notice it).

Leave a comment

Your email address will not be published. Required fields are marked *