六种深色模式
Six Levels of Dark Mode (2024)

原始链接: https://cssence.com/2024/six-levels-of-dark-mode/

这篇文章概述了在网站上实现深色模式的七个级别,从基础到高级。它始于一个观察:许多网站在CSS裸体日(即在没有样式表的情况下查看网站的一天)失去了深色模式功能。 **级别1(简陋)**利用一个简单的meta标签向浏览器发出颜色方案偏好信号。**级别2(基础)**通过CSS应用此设置。**级别3(良性)**引入了`light-dark()` CSS函数来进行简单的颜色调整。**级别4(大胆)**利用媒体查询进行广泛的自定义。**级别5(二分法)**使用通过媒体查询链接的用于亮色和深色模式的单独样式表。**级别6(弹道)**使用JavaScript来检测和应用首选方案。**级别7(超越)**构建自定义颜色方案切换器。 作者还提到了一个**第八级(迷惑)**,使用`:has()`选择器来实现更动态的控制。最终,这篇文章提倡一种分层方法,结合技术来实现强大且易于访问的深色模式,并承认浏览器支持的持续改进和可访问性考虑,特别是对于旧版本的Safari。

黑客新闻 新的 | 过去的 | 评论 | 提问 | 展示 | 工作 | 提交 登录 六种深色模式 (cssence.com) 10 分,Akcium 发表于 3 小时前 | 隐藏 | 过去的 | 收藏 | 1 条评论 帮助 sambellll 发表于 3 分钟前 [–] 如果等级随着你向下滚动页面而生效会很酷。回复 指南 | 常见问题 | 列表 | API | 安全 | 法律 | 申请 YC | 联系 搜索:
相关文章

原文

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.

You could just specify a single entry in the content attribute. Doing so would enforce the corresponding scheme, without taking the user preference into account, but that’s another story.

To some degree, the meta tag is the HTML equivalent of our next level.

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 (e.g. if your content comes from a CMS, poor you), 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.

Both ways essentially give you the option to piggyback on user agent default styles, and the light and dark mode that comes with them. Now add some CSS, but maybe limit yourself to the use of CSS system colors while doing so, and you will already be able to achieve quite neat designs. Heck, the page style switcher on this site has entries named ‘None’ and ‘Basic’, they correspond to levels 1 and 2.

Which brings us to the point where the two ways differ. Unlike the meta tag, which always applies to the whole document, the CSS color-scheme declaration can be set anywhere, not just on the root element. This enables some additional usage scenarios, but I’ll address those in another blog post.

Level 3:
Benign

We are past the basic stage, but still in shallow waters. A rather recent addition to CSS, namely the light-dark() color function, allows for simple light/dark mode adjustments.

html {
	background-color: light-dark(black, white);
	color: light-dark(white, black);
}

The function takes two arguments, both should be colors. The first will be applied in light mode, you may guess what the second argument is for. Whether you simply specify actual colors, or even throw in custom properties that resolve in colors, is up to you.

This is the only part level in this whole blog post where browser support is not great at the time of writing, but we’ll get there.

Level 4:
Bold

Moving on to the good old media query.

@media (prefers-color-scheme: dark) {
	html {
		background-color: black;
		color: white;
	}
}

Whether you query for light or dark, the media query allows for maximum customization, as you are not limited to merely changing colors. You can put anything in there. Wanna use a filter to desaturate images in dark mode? Go for it. Replace box shadows with outlines? Sure.

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">

Dedicated files make sense if you do a lot of customization. The browser may ignore any CSS file that does not match the query, so there’ll be one less thing to download.

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, just like any other media query.

const isDarkScheme = window.matchMedia('(prefers-color-scheme:dark)');

And then do whatever.


In reality, you don’t stay within one lane, you can mix and match the techniques from all the aforementioned levels.

Level 7:
Beyond

You don’t need to solely rely on the user preference, you can build a color scheme switcher.

If you do, be careful, the preference for either light or dark mode is not a boolean state, because initially you want to default to ‘Automatic’, i.e. adhere to prefers-color-scheme. By building a scheme switcher on top of that, you allow the user to opt into one of the three modes.

A color scheme switcher; its dropdown shows entries named ‘Automatic (Default)’, ‘Dark’ and ‘Light’.

If you already knew everything you’ve just read, I’ve got one more for you.

Level 8:
Beguiling

When web developers create a level 7 color scheme switcher, they usually either add a class like .dark to the HTML element, sometimes even a fancy data-theme="dark" attribute.

Well, we no longer need either one, because we can use :has() to query the real deal.

html:has(meta[name="color-scheme"][content="dark"]) {
	--color-bg: black;
	--color-text: white;
}

Check out my accompanying piece »Color scheme switcher, 2024 edition« to see it live.

I definitely saw a couple more sites that had this in their <head>s!

But yes agreed, there’s so much CSS power available lately. When starting a new site from scratch with new styles, you can bake in light and dark modes really easily now. 🙂

In reply to: @[email protected].

Good to hear. Also, seems like we’ve been visiting different sites. 😅

Would a CSS Naked Day webring make sense? 🤔

In reply to: @[email protected].

it seems a bit specific for just naked day… oh, unless it’s done with a nav bar and iframes or something!! Old school…

In reply to: @[email protected].

CSS naked ring? Awesome! I’m in!

Could it be a regular ring but with an url parameter indicating you need to get naked?

Might work for js-naked day too @[email protected].

BTW I’m pretty sure my site did support dark/light preference correctly during naked day. 😉

One thing to note is that up until quite recently (perhaps the latest version), Safari did not have accessible link colours for dark mode. During last year’s CSS Naked Day, I noticed the issue on my website and decided to get rid of the meta tag and just use the light colour scheme. This year I added the meta tag back even though I knew that might create an inaccessible experience for some who might be using the older versions of Safari. I did notice that text boxes did not have any visible borders in Safari with dark mode.

I’ve been starting to think that in the future I might include enough styles to keep my site accessible for CSS Naked Day, since User Agent styles are not fully accessible (even with correct, semantic HTML).

In reply to: @[email protected].

Yeah, good point. Then again, if you look out there realizing how many websites aren’t accessible all year round, April 9 will be the least of our worries.

In reply to: @[email protected], @[email protected].

I almost think seeing the a11y fails on that day is sort of part of it. But it’s good of you to strive to keep it working well for everyone.

I’m curious why there is screen and … in the Bisectional example. The default (when you have no prefix) would be all and …, which has the same effect unless you want to hide styles from printers.

In reply to: @[email protected].

Yes, hiding it from printers was the idea, I would assume they are anyhow taken care of in either a theme-independent core style sheet, or a dedicated print style sheet.

So I guess I wanted to be on the safe side, #DarkMode for printers could waste a lot of ink. 😉

In reply to: @[email protected].

I toggled the system dark more and printed a sample page with the default dark mode styles enabled via the color-scheme. I even tried to enable the “background graphics” option. All I got was black text on white paper. It seems like all browsers don’t apply them to print.

In reply to: @[email protected].

Interesting. I also ran a test: I opened my media queries test page, in the print preview prefers-color-scheme always reports light. Which makes sense. And I guess that’s also the cause for your result. Good to know. (I’ve only been able to test Firefox and Chromium.)

In reply to: @[email protected].

It’s a bummer, though, if you have black paper and white ink, you know. 😄

Get involved

Have your say on Mastodon, or simply share this article.

联系我们 contact @ memedata.com