Dark mode — beyond basics

Wojciech Trawiński
JavaScript everyday
4 min readMay 24, 2024
Photo by Nathan Anderson on Unsplash

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:

light mode (left image) vs dark mode (right image)

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! 🙂

--

--