The prefers-color-scheme media query

Today I want to talk about something, many of you probably like a lot: dark modes! Or more specifically, how to switch the color scheme to dark mode, if visitors prefer it. I do use it for my IDE and for some online services, but for many, I’m still on the light side.

Detecting the dark mode and changing styles

Turning on dark mode is something a user can do in their operating system, in the browser or by clicking a button. Whichever way they choose, your CSS code should use the media query like this:

button {
	padding: 10px 20px;
	font-size: 2rem;
	background-color: #eee;
	border: 3px solid #333;
	border-radius: 10px;
	color: #333;
}
@media (prefers-color-scheme: dark) {
	button {
		background: #333;
		border-color: #333;
		color: #eee;
	}
}

This CSS will expect that you are using a light color scheme by default. If a visitor has set the preference to dark, they will get the alternative colors for the button. This is how a button would look like in light or dark colors:

A button with the text "light colors" on the left, with a light gray brackground-colors and a dark gray text and border-color. A second button on the right with the text "dark colors" and the text in light gray and the background and border in dark gray for a "filled" layout.

By using the same color for background and border, we made the dark version “filled”. You don’t always have to invert/swap all colors. That what some generic plugins do, though. As explained in “Simulate preferences in the browser“, you can easily test those dark mode styles without the need to change the settings in your operating system. Chrome also has an “Automatic dark mode” option, but this would just try to “guess” which colors to use, and we would have a slightly lighter gray for the background and a light gray border:

Two buttons, one labeled "light colors" and one "dark colors". Both have the same colors with a medium gray border, a dark gray background, and a light gray text color.

As you can see, even our defined colors for the dark mode of a button would not apply anymore. Instead, Chrome is displaying any button in this “automatic dark mode”. But I’m also not sure if many people really use this.

Using the light dark mode as the default

Many people design a website with a light mode as the default and then use the media query as shown above to change colors for a dark mode. But if you happen to design a page with a dark mode as the default, that would be a lot of CSS in this media query. What you can do instead: Change colors when a visitor explicitly prefers a light mode. This is how you do it:

button {
	padding: 10px 20px;
	font-size: 2rem;
	background-color: #333;
	border: 3px solid #333;
	border-radius: 10px;
	color: #eee;
}
@media (prefers-color-scheme: light) {
	button {
		background: #eee;
		border-color: #eee;
		color: #333;
	}
}

This code snippet is basically the first one again, with (almost) all colors switched, and with the major different that we now check for light in the prefers-color-scheme media query. The button now looks like this in the default dark mode and in light mode:

Two buttons, the left one with the text "dark colors", and a dark gray background and light gray. The right one with the text "light colors" and a light gray background and dark gray text.

So, depending on your own preference, you can decide which color scheme to use as your website’s default. Adding the other color scheme can make a huge difference in terms of readability and accessibility. Especially when you have a dark mode as a default, please consider offering a light scheme as well.

Conclusion

Adding a dark mode to your CSS was never easier as with this media query. If you want to give users an option to change the mode, a “toggle button” or some user setting can make sense. And for those, another property will come in handy. But this will be the topic for our last blog post in the 2024 advent calendar on CSS.

Posted by

Bernhard is a full time web developer who likes to write WordPress plugins in his free time and is an active member of the WP Meetups in Berlin and Potsdam.

Leave a Reply

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