DEV Community

Lauri Lännenmäki
Lauri Lännenmäki

Posted on

How to create Dark Mode using only CSS

Dark Mode and dark interfaces are not a new thing as they have been a trend for many years. When Apple released a dark mode option with the iOS 13 update back in 2019, the trend took off.

Using modern CSS, you can create dark mode with a few lines of code.

Let's dive in!

📚 Content

✨ Bonus Content


TL;DR;

You can create dark mode using only CSS Custom Properties aka CSS variables and CSS media feature prefers-color-scheme:

/* 1. Create global variables for text and background color */
:root {
  --color-text: black;
  --color-background: white;
}

/* 2. Add conditional styling for dark mode preference */
@media (prefers-color-scheme: dark) {
  /* Re-assign previous variables */
  :root {
    --color-text: white; /* black => white */
    --color-background: black; /* white => black */
  }
}

/* 3. Assign variables to page color and background */
body {
  color: var(--color-text);
  background-color: var(--color-background);
}
Enter fullscreen mode Exit fullscreen mode

That's it 🔥 View my CSS Only Dark Mode Codepen.


Dark mode is more than a trend

Dark mode is not a design trend. Dark interfaces can be easier on the eyes and reduce eye strain and fatigue. They can actually help reduce the sensation of discomfort felt when staring at websites with light backgrounds.

Dark mode also saves your device's battery life. It can reduce battery usage, especially on mobile devices.


Dark mode is accessibility

Dark mode is also an accessibility (a11y) feature. It's about respecting your users and their preferences so they can use your website the way they like.

Besides responsive media queries, modern CSS has many cool media features and prefers-color-scheme is one of them. Quote from MDN Web Docs 👇

The prefers-color-scheme CSS media feature is used to detect if the user has requested a light or dark color theme. The user might indicate this preference through an operating system setting (e.g. light or dark mode) or a user agent setting.

Users can choose if they prefer light or dark mode from their operating system settings.

Picture from macOS general settings.

(macOS)

Picture from iOS Display & Brightness settings.

(iOS)

With CSS, you can serve the user the theme they prefer. Media queries are used to conditionally apply styles. Media feature prefers-color-scheme is a Media Query, so you write it like you'd write your breakpoints:

/* Breakpoint */
@media (min-width: 800px) {
  /* Add conditional styles here */
}

/* Prefers Color Scheme */
/* Dark */
@media (prefers-color-scheme: dark) {
  /* Add conditional styles here */
}
/* Light */
@media (prefers-color-scheme: light) {
  /* Add conditional styles here */
}
Enter fullscreen mode Exit fullscreen mode

How to set up dark mode with CSS

Create CSS Custom Properties (variables)

To setup color styles, I recommend using variables to keep your code DRY (don't repeat yourself). If you aren't familiar with CSS variables, you can read about them from MDN Web Docs.

For the sake of this tutorial we keep things simple and use black and white as our colors. And we only style our text color and background color.

/* 1. Create global variables for text and background color */
:root {
  --color-text: black;
  --color-background: white;
}
Enter fullscreen mode Exit fullscreen mode

Create conditional styling

Next, let's apply conditional styling for users who prefer dark mode. By using a media query, we re-assign previous variables with new inverted values.

/* 2. Add conditional styling for dark mode preference */
@media (prefers-color-scheme: dark) {
  /* Re-assign previous variables */
  :root {
    --color-text: white; /* black => white */
    --color-background: black; /* white => black */
  }
}
Enter fullscreen mode Exit fullscreen mode

Apply styles

And finally, we apply the variables to our design:

/* 3. Assign variables to page color and background */
body {
  color: var(--color-text);
  background-color: var(--color-background);
}
Enter fullscreen mode Exit fullscreen mode

Demo and final code

See the final effect in action of user changing between light and dark mode in OS settings:

GIF animation of user changing between light and dark mode in OS settings.

👇 The final code in full.

/* 1. Create global variables for text and background color */
:root {
  --color-text: black;
  --color-background: white;
}

/* 2. Add conditional styling for dark mode preference */
@media (prefers-color-scheme: dark) {
  /* Re-assign previous variables */
  :root {
    --color-text: white; /* black => white */
    --color-background: black; /* white => black */
  }
}

/* 3. Assign variables to page color and background */
body {
  color: var(--color-text);
  background-color: var(--color-background);
}
Enter fullscreen mode Exit fullscreen mode

You can view the code and play with it in my Codepen.


✨ Bonus Content

Color-scheme meta tag and CSS property

The color-scheme meta tag and CSS property takes care of two important things for you. This next quote is from Google Developers web.dev and I've taken the liberty to highlight some parts of it 👇

They both make your life as a developer easier by allowing you to opt your page in to theme-specific defaults of the user agent stylesheet, such as, for example, form controls, scroll bars, as well as CSS system colors. At the same time, this feature prevents browsers from applying any transformations on their own.

By the order of values, you can determine the default appearance. Here's the syntax for both CSS and the corresponding HTML meta tag:

:root {
  color-scheme: dark light;
}
Enter fullscreen mode Exit fullscreen mode

(In the CSS example, the page author prefers dark theme.)

<head>
  <meta name="color-scheme" content="light dark">
</head>
Enter fullscreen mode Exit fullscreen mode

(In the HTML example, the page author prefers light theme.)

It is recommended to specify the color-scheme via the meta tag, so the browser can adopt to the preferred scheme faster.


How to test your code

Google Chrome Dev Tools

You can test your code with Google Chrome Dev Tools.

  1. Open up your Dev Tools Inspection panel by pressing Command+Option+C (Mac) or Control+Shift+C (Windows, Linux, Chrome OS).
  2. Click on the three dots in the upper right corner => select More tools => click Rendering.
  3. From the Rendering tab you can find the emulation for prefers-colors-scheme.

See the screenshots below 👇

Image of Google Chrome Dev Tools' Rendering tab highlighting prefers-color-scheme emulation.

Image of Google Chrome Dev Tools' Rendering tab prefers-color-scheme emulation turned to emulate dark mode.

Device OS settings

As shown before, you can change the appearance from you device settings. Screenshots are from macOS and iOS. You can find the same settings from Android and Windows devices.

Picture from macOS general settings.

Picture from iOS Display & Brightness settings.


Resources and further reading

  • CSS Only Dark Mode Codepen by me
  • Color-scheme meta tag and CSS property at web.dev
  • CSS Media Feature prefers-color-scheme at MDN Web Docs
  • CSS Custom Properties aka CSS Variables at MDN Web Docs

Thank you 🙏

I hope you found this article helpful 🔥

You can follow me on Twitter for more CSS, Design System and Figma content 💪

Top comments (1)

Collapse
 
roblevintennis profile image
Rob Levin

Nice article! I have done partial dark mode switching support a few times and at this point I think the next one will likely support in order:

  1. User settings (assuming something of persistent store)
  2. Automatic (schedule based adjustmed like MacOS supports 3 Prefers system settings
  3. Fallback defaults

Maybe 2 and 3 are one in same. The class on body tag custom properties flip works pretty well otherwise.