Dark mode — beyond basics
Today, it’s almost a given that applications should support dark mode. Users expect that operating system level settings will apply to each installed native application and the websites they visit.
A common method to address these needs is to use the prefers-color-scheme
media feature. However, theming is often limited to CSS declarations:
:root {
@media (prefers-color-scheme: light) {
--background-color: #fff;
--text-color: #000;
}
@media (prefers-color-scheme: dark) {
--background-color: #000;
--text-color: #fff;
}
}
body {
background-color: var(--background-color);
color: var(--text-color);
}
Alternatively, you can extract CSS declarations for different themes into separate files and activate them based on user preference:
<!DOCTYPE html>
<html lang="en">
<head>
...
<link
rel="stylesheet"
media="(prefers-color-scheme: light)"
href="light-theme.css"
/>
<link
rel="stylesheet"
media="(prefers-color-scheme: dark)"
href="dark-theme.css"
/>
<link rel="stylesheet" href="styles.css" />
...
</head>
...
</html>
// light-theme.css
:root {
--background-color: #fff;
--text-color: #000;
}
// dark-theme.css
:root {
--background-color: #000;
--text-color: #fff;
}
It’s important to note that both stylesheets are downloaded, but with different priorities. The inactive theme file does not contribute to the Critical Rendering Path:
light mode active
dark mode active
To test how your application appears with different user preferences, you can adjust the settings in Chrome DevTools:
While it’s a solid start for enhancing user experience, there’s more you can do to honor a preferred color scheme. Let’s explore which user interface elements can be adjusted accordingly.
favicon
The favicon can be provided in SVG format, which can adapt to the active theme:
<!DOCTYPE html>
<html lang="en">
<head>
...
<link rel="icon" type="image/svg+xml" href="favicon.svg" />
...
</head>
...
</html>
// favicon.svg
<svg height="100" width="100" xmlns="http://www.w3.org/2000/svg">
<style>
@media (prefers-color-scheme: light) {
circle {
fill: red;
stroke: black;
}
}
@media (prefers-color-scheme: dark) {
circle {
fill: black;
stroke: red;
}
}
</style>
<circle r="45" cx="50" cy="50" stroke-width="5" />
</svg>
theme-color
Media queries enable the customization of an application’s hosting environment (such as a browser) through the theme-color
setting:
<!DOCTYPE html>
<html lang="en">
<head>
...
<meta
media="(prefers-color-scheme: light)"
name="theme-color"
content="#c932b8"
/>
<meta
media="(prefers-color-scheme: dark)"
name="theme-color"
content="#6b6b6b"
/>
...
</head>
...
</html>
default browser styles
If dark mode is active, a browser may take it into account when applying its default styles (user agent stylesheets) via color-scheme
CSS property. In addition, the accent-color
CSS property defines the highlight color used within form elements:
:root {
@media (prefers-color-scheme: light) {
color-scheme: light;
--background-color: #fff;
--text-color: #000;
--accent-color: #c932b8;
}
@media (prefers-color-scheme: dark) {
color-scheme: dark;
--background-color: #000;
--text-color: #fff;
--accent-color: #6b6b6b;
}
accent-color: var(--accent-color);
}
Additionally, the light-dark()
function could be useful:
:root {
color-scheme: light dark;
--background-color: light-dark(#fff, #000);
--text-color: light-dark(#000, #fff);
--accent-color: light-dark(#c932b8, #6b6b6b);
accent-color: var(--accent-color);
}
images
Last, but not least, you can render different image for dark mode using the picture
element:
<!DOCTYPE html>
<html lang="en">
...
<body>
<h1>The Timeless Ford Mustang</h1>
<picture>
<source
srcset="mustang-light.jpg"
media="(prefers-color-scheme: light)"
/>
<source
srcset="mustang-dark.jpg"
media="(prefers-color-scheme: dark)"
/>
<img src="mustang-light.jpg" alt="Ford Mustang - iconic muscle car" />
</picture>
...
</body>
</html>
Here’s a comparison for light / dark modes:
If you want to dive deeper into the topic, I recommend taking a look at the following resources
As a frontend developer, you must pay attention to user experience issues and a full-fledged support for dark mode is undoubtedly one of the areas worth consideration.
I hope you liked my story, thanks for reading! 🙂