Six Levels of Dark Mode (2024)

A comprehensive guide exploring various techniques to implement dark mode, ranging from simple HTML meta tags to advanced CSS functions and JavaScript integration.
Being reminded of the visually hidden debate hasn’t been the only thing that happened to me on this year’s CSS Naked Day.
I’ve observed that on pretty much all the sites I’ve visited, dark mode was rather absent after the styles had been removed. This got me thinking, maybe it’s time to talk about the six levels of dark mode.
A less catchy—but more accurate—title for this blog post would have been “six levels of color scheme switching”. Oh well. Most of the example code in this article shows the dark side, so the title does make sense. Just keep in mind that the other way around also works.
Enough said, let’s get to it.
Level 1: Barebone
This level is as easy as it gets, but apparently the underlying directive was missing on the sites mentioned in the introduction. You can opt into light/dark mode differentiation even without a single line of CSS, which is great in general, but especially on April 9.
Simply add the following meta tag to the document head, and you are good to go.
<meta name="color-scheme" content="light dark">
Whenever a web page contains this tag, the browser knows it should adhere to the user’s color scheme preference. The order of the entries in the content attribute matters, at least in theory. Users without a preference for a color scheme would get the first in the space-separated list. But the settings in today’s operating systems lack the option to not choose one, so you’ll always end up with the one that matches the OS.
Level 2: Basic
Let’s move on to the CSS way of light/dark mode differentiation.
html {
color-scheme: light dark;
}
You won’t need this declaration if you already have the meta tag in the DOM. Unless you have no control over the HTML, I encourage you to always use the meta tag. This gives the browser a head start, as it already knows about the color scheme directive before any CSS has been parsed.
Level 3: Benign
A rather recent addition to CSS, namely the light-dark() color function, allows for simple light/dark mode adjustments.
html {
background-color: light-dark(white, black);
color: light-dark(black, white);
}
The function takes two arguments, both should be colors. The first will be applied in light mode, the second for dark mode.
Level 4: Bold
Moving on to the good old media query.
@media (prefers-color-scheme: dark) {
html {
background-color: black;
color: white;
}
}
The media query allows for maximum customization, as you are not limited to merely changing colors. You can put anything in there, like filters or layout changes.
Level 5: Bisectional
You can use the media query in HTML too. Adding it as a media attribute allows you to create style sheets for each scheme.
<link media="screen and (prefers-color-scheme:light)" rel="stylesheet" href="light.css">
<link media="screen and (prefers-color-scheme:dark)" rel="stylesheet" href="dark.css">
Level 6: Ballistic
Obviously JavaScript wants to play a part in this too. You can use the matchMedia function to query for either light or dark scheme.
const isDarkScheme = window.matchMedia('(prefers-color-scheme:dark)');
Level 7: Beyond
You don’t need to solely rely on the user preference, you can build a color scheme switcher. By building a scheme switcher, you allow the user to opt into one of the three modes: Auto, Light, or Dark.
Level 8: Beguiling
When web developers create a level 7 switcher, they usually add a class like .dark. Well, we no longer need that, because we can use :has() to query the meta tag directly.
html:has(meta[name="color-scheme"][content="dark"]) {
--color-bg: black;
--color-text: white;
}
Source: Hacker News










