A Bit Of Access

Toggle dark mode on your website by user preference

Published by

If you have implemented a dark mode on your website, or are planning to do so, a nice addition to this is toggling it automatically for your users who have a dark color scheme preference set in their operating system.

In this article we'll explore using the prefers-color-scheme media feature through media queries in CSS and Javascript to act on the dark color scheme setting in the following segments:

  1. Prefers-color-scheme media feature in CSS
  2. Prefers-color-scheme media feature in Javascript
  3. Acting on preference changes in Javascript

Compatibility: While this function has wide support, it is still experimental and not supported on Opera, IE, and Edge (this might change when Edge changes render engine soon). Implementing this should be considered a nice to have feature, be careful not to let any other functionality depend on it.

Links to documentation: In the CSS examples the property names, and pseudo classes and elements link to their MDN web docs pages.

Prefers-color-scheme media feature in CSS

Media queries are very useful in CSS, it's what makes it possible to change styles depending on window size for example. Using media queries, we can also find out what color scheme preference a user has set.

Let's imagine the most basic style we can, only setting a color for text and background, and a color for our links.

body {
	background-color: #C7C7C7;
	color: #0F1919;
}
a {
	color: #196160;
}
CSS: simple style for the body and link elements.

Now, we can imagine our dark mode can be very simple too, by just switching these colors around. We can do that by putting it in a media query checking for prefers-color-scheme. Prefers-color-scheme has 3 possible values:

  • no-preference: user has no set preference
  • light: user prefers a light color scheme
  • dark: user prefers a dark color scheme

With these possibilities, we now know we want to apply our dark mode when the prefers-color-scheme is "dark". It might look like this.

@media (prefers-color-scheme: dark) {
	body {
		background-color: #0F1919;
		color: #C7C7C7;
	}
	a {
		color: #40CECC;
	}
}
CSS: simple style for the body and link elements when a dark color scheme is preferred.

Within a media query block you can add all your CSS that applies to that rule. This works well, and won't break if the browser does not support it, defaulting to the original light colors and ignoring the media query.

A drawback of using only CSS is that it does not allow the user to switch back to your default style. Let's take a look at our options with JavaScript next.

Prefers-color-scheme media feature in Javascript

For Javascript, imagine we already implemented a toggle on our website that switches between a light and dark color scheme. For this we could have a .darkmode class we toggle on our html element using JavaScript, and our simple CSS might now look like this.

body {
	background-color: #C7C7C7;
	color: #0F1919;
}
a {
	color: #196160;
}
html.darkmode body {
	background-color: #0F1919;
	color: #C7C7C7;
}
html.darkmode a {
	color: #40CECC;
}
CSS: simple style for the body and link elements, with changes when the html element has a class named darkmode.

To toggle dark mode by default if a user has this preference, we will check the prefers-color-scheme media feature using the window.matchMedia() function in Javascript.

We will by using the matches property to get a true or false value from our query. As you will see in the following example, the query is the same one we used in our CSS previously.

var preference = window.matchMedia('(prefers-color-scheme: dark)');
if (preference.matches) {
	// A dark color scheme preference is set so we add the class from our html element
	document.documentElement.classList.add('darkmode');
} else {
	// No dark color scheme preference is set so we remove the class from our html element
	document.documentElement.classList.remove('darkmode');
}
Javascript: checking if the user has set a preference for a dark color scheme.

With this bit of JavaScript in your page the dark mode class will be added to, or removed from, your html element when the JavaScript is run.

Acting on preference changes in Javascript

What about a user changing their preference while they're on your site? In CSS this will change will automatically apply, but in JavaScript we will have to make sure we keep an ear out by adding a listener.

What we'll do is wrap our check in a function, call that function so it will be run once when the page is opened, and add a listener to run the function when the preference changes.

var preference_query = window.matchMedia('(prefers-color-scheme: dark)');
function checkPreference(query) {
	if (query.matches) {
		// A dark color scheme preference is set so we add the class from our html element
		document.documentElement.classList.add('darkmode');
	} else {
		// No dark color scheme preference is set so we remove the class from our html element
		document.documentElement.classList.remove('darkmode');
	}
}
checkPreference(preference_query);
preference_query.addListener(checkPreference);
Javascript: checking if the user has set or changes a preference for a dark color scheme.

With this function and listener in place, the class will automatically be added or removed when the JavaScript is run and whenever the preferred setting is changed.

Depending on how you toggle your dark mode, you might need to add a few lines of code to make sure your toggle correctly communicates the current setting.

Notes on accessibility

Aside from prefers-color-scheme there are other media features you might want to consider using from an accessibility standpoint, such as prefers-contrast and prefers-reduced-motion so users that have set these preferences have a more pleasant and accessible experience on your website.

Relevant documentation: