夜间模式🌚🌝与混合模式的区别
我在准备我的演讲《This World Mixed and Blended》 (这些幻灯片需要彩色字体支持,例如 FireFox / Safari)时萌生了实现夜间模式 的想法。最初的想法只是为了展示,而且目前浏览器支持有限。mix-blend-mode: difference
尽管如此,我还是把它实现到我的开发博客上,并且玩得很开心。所以这篇文章就是关于这个的。同时,随着我进一步思考,我发现这或许可以成为实现夜间模式的一种更合适的方式。让我也分享一下背后的一些想法。
请注意,这不是实现暗黑模式的标准方法。想了解大家通常的做法,你可以看看Dan Abramov 在 Overacted 上的做法,或者看看这篇文章。

理解mix-blend-mode: difference
mix-blend-mode: difference
是 CSS 支持的混合模式之一,具体定义在“合成与混合级别 1”中。混合模式则指定了图形堆叠时颜色的混合方式。图形不限于图像。任何渲染的图形、div 内容、文本、表情符号🌚🌝、SVG 等都可以参与混合。
我想将其视为浏览器在绘制新元素时与我们核对的过程:“嘿,看来我绘制的下一个像素是红色的,但目前我看到地面是蓝色,您是否希望我将这些颜色组合在一起,如果是的话,怎么做?”
混合模式允许我们创建一些非常有趣的效果,例如在图像上叠加文本,同时直接在浏览器中显示图形的纹理:
合成和混合级别 1中的混合模式示例
定义
mix-blend-mode: difference
具体来说,是一种混合模式,其定义为取两种颜色之间的差异的绝对值:
difference(A, B) = |A - B|
这是实际计算的抽象,其中对于每种颜色,我们用三个数字分别代表 R、G 和 B 通道。例如,
difference(
rgb(255, 255, 255),
rgb(0, 100, 200)
) = rgb(255, 155, 55)
同时,取绝对值使得运算可交换,即B(A, B) = B(B, A)
。换句话说,无论哪个图形放在另一个图形上面,结果都是一样的。
直觉
混合模式的“差值”究竟起什么作用?定义看似简单。然而,在实际看到最终颜色之前,我们的大脑可能无法很好地感知到最终颜色的变化。举个例子,difference(white, red)本质上是在推断红色的补色,也就是青色。但是,除非你真正看到它,否则你怎么能“看到”它呢?
下面的笔是通过混合白色和红色的相交条纹创建的。
也许正是因为它的效果难以察觉,我们可以利用它创建一些对比鲜明的视觉效果来在 UI 中引发惊喜,就像Sven Wolfermannmix-blend-mode: difference
的这个一样:
这个设计启发了我思考如何使用差异来创建暗模式。
使用以下方式实现暗黑模式mix-blend-mode: difference
它是如何工作的?
background: white
这个想法很简单:当夜间模式打开时,用 和的全屏 div 覆盖您的网站mix-blend-mode: difference
,并省去再次定义所有颜色的麻烦😉
.dark-mode-screen {
width: 100vw;
height: 100vh;
position: fixed;
top: 0;
left: 0;
background: white;
mix-blend-mode: difference;
}
但为什么呢?
这个思维过程涉及数学家最喜欢的两个数字:0 和 1。
在单位空间中,0 表示无,1 表示有。
在 RGB 颜色中,0 表示黑色,1(100% 或 255)表示白色。
现在让我们想象一下我们的博客网站,假设我们现在有一个白色背景和一个黑色前景。如果我们把这个页面与白色的差异取下来,我们会得到什么?
- 背景:目前是白色,和白色没什么区别,也就是黑色
- 前景:目前是黑色,代表什么都没有,白色和什么都没有的区别就在于白色
现在我们有了黑色背景和白色前景,看看那是什么?反转(深色)主题 :)
此外,当提取页面与白色之间的差异时,原始背景和前景之间的对比度会自动保留。这不仅适用于黑色和白色。事实上,我使用原始主题“Dracula”的代码块在反转后会呈现出漂亮的棕褐色调。
过渡
缩放 div
我在页面底部固定了一个开关。当夜间模式切换时,我会将这个开关放大并覆盖整个页面。这种效果在某种程度上展现了最初的用户体验设计。

不透明度
如果您更喜欢更细微的切换,或许微调一下opacity
是个更好的选择,混合模式也能达到同样的效果。由于过渡效果带有缓和时间的功能,这或许是大多数实现夜间模式的网站和博客所采用的过渡界面。

隔离不打算混合的元素
如前所述,mix-blend-mode
适用于任何图形。但是,在实现暗黑模式时,某些元素可能不需要混合。例如,特定颜色的徽标、表情符号等。要指定这种情况,您可以在这些元素上放置isolation: isolate
(引用)。请注意,这会在被隔离的元素上创建一个堆叠上下文。
/* twitter logo and emoji should not blend */
.twitter-logo,
.emoji {
isolation: isolate;
}
/* elements that create their a stacking context are automatically isolated */
.footer {
z-index: 1;
}
为你的黑暗模式选择一种色调
如前所述,取页面与白色之间的差异就像直接取补色一样。您不必将颜色选择限制为白色。事实上,您可以选择任何颜色来取差异。为了在网站最初采用浅色背景的情况下实现较暗主题的效果,您可以考虑任何相对较浅的颜色:

这些是我遇到的一些技术细节。如果您在尝试过程中遇到任何问题,请随时告诉我,我很乐意为您提供帮助。
要在代码中查看此内容,请查看此 CodePen:
限制
(除了有点怪异之外😅)
- 你没有完整的颜色范围。这省去了你指定更多颜色的麻烦,但你会失去对深色的控制——它们会从浅色中推断出来。然而,这可能不是一个限制,而是一个设计选择。
- 的浏览器支持
mix-blend-mode
仍然不是最佳的,您只能使用非 IE 且相对较新版本的浏览器。 - 由于其逐像素和逐通道计算,性能也可能是一个问题。暂时不要用它做疯狂的动画。
下次再见🤞
混合模式源自计算机图形学。我记得几年前第一次在 Photoshop 中玩它们。如今浏览器功能越来越强大,我们看到了浏览器渲染原生的复杂图形功能。但这并不意味着我们应该在浏览器中实现完整的 Photoshop,也不应该将我们的想象力局限于此。浏览器和网页有各自的使用场景和目标,以及不同的限制。或许我们应该像欢迎新居民一样欢迎它们,并探索它们在各自领域的原生用例。
再次感谢CodePen 上的这个动画,它可爱极了,让人一眼就印象深刻。不妨把鼠标悬停在它上面🙈
我希望这可以成为您关于混合模式的一个友好发现,并且希望您和我一样享受乐趣。
鏂囩珷鏉ユ簮锛�https://dev.to/wgao19/night-mode-with-mix-blend-mode-difference-23lm