Dark Mode

How to use Atomizer to enable dark mode on your site.

Dark mode has become a standard feature across many websites. OS level support and the prefers-color-scheme CSS media feature have made it even easier to enable dark mode.

Atomizer does not provide out-of-the-box support for dark mode because it is not required. You can combine the prefers-color-scheme CSS preference and the existing context class support to add dark mode to your website.

Continue reading to learn how to use each concept.

Browser Basics

All modern browsers support the prefers-color-scheme CSS media feature. The feature works by defining or overwriting an existing CSS property via the @media (prefers-color-scheme: dark) {} directive.

In the example below, we set an initial style for a div with the .intro class. We overwrite the style when the OS or user-agent preference is set to dark.

<div class="intro">Hello World!</div>
/* initial style */
.intro {
    background: #eee;
    color: black;
}

/* overwrite colors for dark mode */
@media (prefers-color-scheme: dark) {
    .intro {
        background: #333;
        color: white;
    }
}
Hello World!
Hello World!

With Atomizer

In Atomizer, you can leverage the context class syntax to apply styles based on the existence of a class earlier in the HTML tree.

In the example below, the default styles for the div would be background-color: #eee; and color: #000;.

<div class="Bgc(#eee) C(#000)">Hello World!</div>

You can prepend a class, dark (the name is arbitrary and can be whatever you want) to styles you want to override in dark mode.

- <div class="Bgc(#eee) C(#000)">Hello World!</div>
+ <div class="Bgc(#eee) C(#000) dark_Bgc(#333) dark_C(#fff)">Hello World!</div>

When the dark class is added earlier in the HTML tree, the styles will change to background-color: #333; and color: #fff.

<body class="dark">
    <div class="Bgc(#eee) C(#000) dark_Bgc(#333) dark_C(#fff)">Hello World!</div>
</body>

By default, nothing will happen, even if the user has the dark mode scheme enabled. You would need to add the dark class to your website to "enable" the dark mode classes. Read the Enabling Dark Mode section for tips on how to add the class to your project.

Optimizing with CSS Variables

You could further optimize the approaches mentioned above by combining with CSS custom properties (a.k.a CSS variables) to manage the color changes via the prefers-color-scheme media feature. Building off the examples above, you would move the color definitions to an external style sheet managed outside Atomizer.

The example below defines the default colors in the :root block, and their dark mode overrides via the prefers-color-scheme block.

/* define the default colors */
:root {
    --background-color: #eee;
    --text-color: #000;
}

/* overrides for dark mode */
@media (prefers-color-scheme: dark) {
    :root {
        --background-color: #333;
        --text-color: #fff;
    }
}

You would use the CSS variables instead of the hardcoded hex values in your HTML.

<div class="Bgc(--background-color) C(--text-color)">Hello World!</div>

The benefit of this approach is that you use the built-in prefers-color-scheme browser feature and reduce the number of classes you need to manage in the markup.

Enabling Dark Mode

If the CSS variable approach is not possible for your website, you will need to output the class in your HTML tree to enable dark mode. How you add the class will depend on your website architecture.

Server-side Rendered

A server-side rendered website creates the HTML markup on the server. Based on the Request context of the user, the HTML markup can be personalized. For dark mode support, you could add the dark class to your HTML based on some preference from the user.

There are a few different ways to do this; we briefly describe them below.

Client-side JavaScript (outside the scope of this guide) allows the user to choose their preference (light or dark mode). Once selected, you store their choice in a Cookie sent on subsequent requests to your site.

Your server-side code would then read the color-scheme preference from the cookie and output the dark class based on this preference.

Client Hints

You can request a set of HTTP headers from the browser to get information about the device and user preferences. The Sec-CH-Prefers-Color-Scheme header is relatively new (as of this writing), and modern browser support is ongoing. However, for those browsers that support it, you can get access to the user’s color-scheme preference via this HTTP header on the server.

Your server-side code would initially request this header from the browser, which would return the user’s preference. As you generate the server-side markup, you can determine whether to output the dark class based on this header.

Please check out the this web.dev article for more information.

Static-site Generated

A statically generated site creates its markup at build time. Unpersonalized HTML markup is delivered and will not be adapted to a user’s preference.

This Atomizer website is statically generated and leverages the CSS variables approach to toggle between light and dark mode.

Since you cannot modify the markup on the server, you can leverage JavaScript to add the dark class to your HTML. The code below uses the Window.matchMedia() API to check the users preferred color scheme. If dark is chosen, then the dark class is added to the <html> node.

<head>
    <!-- website css ... -->
    <script>
    if (window.matchMedia('(prefers-color-scheme: dark)').matches) {
        document.documentElement.classList.add('dark');
    }
    </script>
</head>

Add the script in your website’s <head> tag to guarantee the dark class is added as soon as possible to avoid a flash of light to dark style.

Client-side Rendered

Client-side rendered websites generate their markup in the browser. Similar to the Static-site Generated approach, the Window.matchMedia() API can be used to add the dark class.

The JavaScript you write to add the class will depend on your framework of choice and is outside the scope of this document. In general, you will need to add the dark class to the component or JavaScript file that outputs your project’s <html> element.