Embracing Dark Mode on the Web

Following the macOS Mojave release last year, which introduced dark mode to the Mac, iOS 13 will include its own system-wide dark mode feature when it launches this fall. This was of great importance to iOS app developers, many of who will be updating their apps to support dark mode. But I think there's something that's being left out, and that's the web.

Anyone who uses dark mode can testify as to how jarring it is to come across an application that only supports a bright color scheme. It's especially blinding in low-light environments where dark mode is often used. The same applies to webpages.

Screenshot showing Wikipedia open in a browser with a dark appearance

To avoid this visual clash, websites should start including a dark color scheme, just like native applications are doing— especially with how much the gap between the two has shrunk. I think this is a substantial user experience improvement for those who have dark mode enabled.

This is nothing new— plenty of websites have already implemented their own custom dark mode options. What's more recent is a standard for creating web pages which can automatically adapt to the system color scheme.

CSS

In CSS, you can determine if the user has either light mode or dark mode enabled using the new prefers-color-scheme media query (MDN docs). The possible values here are light, dark, and no-preference. This feature is recent so browser support for it is pretty sparse for now.

You can implement this without negatively affecting users with unsupported browsers by using the media query to override the base color scheme. Browsers that don't support prefers-color-scheme will just see the base colors.

body {
	color: black;
	background-color: white;
}

@media screen and (prefers-color-scheme: dark) {
	body {
		color: white;
		background-color: black;
	}
}

There's another element that you may need to consider if you want to make the most of dark mode, and that's the system form controls. On macOS, the system-style form controls have a different appearance in light mode and dark mode.

Comparison of light and dark controls on macOS

You will be able change these elements to their dark appearance with the proposed color-scheme property. Note that in Safari 12.1, this property was called supported-color-schemes instead. I'd recommend declaring both for now to support more versions of Safari.

JavaScript

You may also want to detect if the user has dark mode enabled from JavaScript. To do this, you can use the matchMedia API (MDN docs), which allows you to evaluate media queries from JavaScript. Combined with the prefers-color-scheme media query, you can easily determine if dark mode is enabled.

Here's a simple implementation:

function isDark() {
	return window.matchMedia('(prefers-color-scheme: dark)').matches;
}

It's also possible to add an event listener which will activate whenever the user switches their system between light and dark mode.

let mQuery = window.matchMedia('(prefers-color-scheme: dark)');
mQuery.addListener(e => {
	// Handle light/dark mode switch here
	if (e.matches) {
		alert('Dark mode is enabled');
	} else {
		alert('Dark mode is no longer enabled');
	}
});

As for browser support, the matchMedia API itself is well supported, but the limitations of the prefers-color-scheme media query still apply. The matches property will just evaluate to false if the media query isn't supported, which should be fine in most cases.

If needed, you can explicitly check if the browser supports the media query with this snippet: Update: This approach no longer works.

window.matchMedia('(prefers-color-scheme)').media !== 'not all';