让网站适配 Dark Mode

在 macOS 发布了 10.15.1 这个体积超大的更新版之后,决定这个周六把开发机(10.14.6)升级了,毕竟是开发机只能一直在新版和稳定的边缘试探🤪。

然而我的手机早就已经升级到最新版的 13.2 了,其中最让我不爽的是 iOS13 的「Reminders」竟然是和 Mojave 不兼容的,Apple 竟然搞出这样的骚操作来。

丫的系统版本刷新得倒挺快,这么重要的 APP 最起码的向下兼容竟然不搞,学互联网公司的作风得学全套啊🤷🏻‍♂️。

iOS UI 层面感受最深刻的就是 Automatic Dark Mode(自动暗黑模式),Mojave 虽然也有 Dark Mode,但是不能自动切换。

个人感觉在使用上白天还是 Light Mode(浅色模式)好用,所以晚上就得手动切换,然后就懒得用了,能自动化操作的事情为什么要让用户手动切换?

Night Shift(夜览)就很赞,切换得很自然。

好在 Catalina 终于也支持了 Automatic Dark Mode,然后发现适配 Dark Mode 的网页太少了,系统和网页对比,太突兀了。

当然 Dark Mode 出来没多久,适配还是需要时间,许多 APP 都还没适配更别提网页了,甚至连 Apple 官网都还没适配呢,所以我当时就决定,先把我自己的博客给适配了。

美好的事物总是会来的🙆🏻‍♂️。

首先是收集相关的技术信息。

针对 Dark Mode 已经有相关的规范:

https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-color-scheme

The prefers-color-scheme CSS media feature is used to detect if the user has requested the system use a light or dark color theme.

技术上就是通过 CSS 媒体类型标签 @media 和 系统主题这个特征 prefers-color-scheme 在 CSS 层面由浏览器做样式计算然后渲染,当然还可以定义其他主题样式:light、grey 啥的。

:root {
  --background-color: #FFF;
}

@media (prefers-color-scheme:dark) {
  --background-color: #000;
}

.body {
  background-color: var(--background-color);
}

涉及到前端我们得知道现在浏览器对该特征的支持情况:

https://caniuse.com/#search=prefers-color-scheme

按照 Apple 开发规范,iOS 版的微信用的是 Safari 内核,理论上应该是支持的,但是现实打脸了,不知道中间做了什么 “优化”。

了解了实现原理之后,就知道适配主要就是对颜色、对比度、透明度等等 CSS 属性的处理,页面结构其实并没有变化,所以接下来就是处理颜色。

因为没有设计师,我只能先去了解关于 Dark Mode 的设计规范,然后自己鼓捣一番。

Apple Visual Design: https://developer.apple.com/design/human-interface-guidelines/ios/visual-design/dark-mode/

Google Material Design: https://material.io/design/color/dark-theme.html

网友分享的颜色搭配:https://colorhunt.co/palettes/dark

设计师的经验:https://www.zcool.com.cn/article/ZMTAxMjAxNg==.html

一番实验后,终于确认了颜色搭配,然后就是编码实战了。

因为我的博客本身走的是简约风,所以 Light Mode 大都是 黑、灰、白,虽然颜色都很接近,但实际上却不相同,灰色都有好多种😩,真 “你说的灰是什么灰,你说的白是什么白”。

尝试 N 次之后,终于确认了最终版颜色,颜色的搭配很重要,不然会出现对比度太高,亮瞎眼,对比度太低,看得很费劲,最终都降低可读性。

小建议,不能完全追求纯黑,这样对整体背景还是不能太黑,如果太黑,文字的对比度很高,并不适合阅读,这块可以参考下 Apple 的自带 APP 的设计,比如 Safari:

safari-dark-mode

顺利得有点诡异,果不其然,验收测试的时候掉入了另外一个坑:第三方组件适配。

修改完毕后,博客本身是能支持 Dark Mode 了,但是作为一个技术博客最主要的代码高亮不支持🤦🏻‍♂️。

因为 @media 本质上是一个 CSS 的语法,作用域有限,所以需要第三方组件自身支持 Dark Mode 才行。

经过梳理之后,很幸运,本博只引用了代码高亮这一个外部组件,针对性做处理即可。

但是毕竟是第三方组件,也不能去修改其源码,于是干脆分 Dark 和 Light 两种模式,各采用一种主题即可🤓 。

使用同时为了优化性能,减少额外的资源加载,通过模式的不同,直接加载不同的 CSS 主题资源即可,Javascript 简化代码如下:

if(window.matchMedia("(prefers-color-scheme:dark)").matches){
	// load dark mode theme css
}else{
	// load light mode theme css
}

测试通过。

自此本博 Dark Mode 支持完毕。

整个适配过程其实主要是颜色的搭配和替换,更多的是一个体力活。

本博还算是很简单的,因为页面简单、样式分离比较彻底,所以改动点都很聚焦,现在的 APP 都走的是模块化、插件化了,那适配起来各个模块都得改,更别提微信这样有大量第三方服务接入的 APP 了,成本不言而喻,也能理解 APP 的适配难度了,不是换个颜色就行的,还得考虑用户体验,不能产生新的割裂感。

并且适配 Dark Mode 并没有明显的收益,ROI 太低,也是企业不积极的原因吧。

但是如果公司结构比较合理,包括但不限于:技术架构、部门架构,这样设计规范统一、技术组件统一,甚至只用批量处理即可低成本完成适配。

好的架构真的是项目进步的基石。

当然随着大家对 Dark Mode 的接纳度越来越高,适配方也会越来越多,美好的事物总是值得被推崇的🙆🏻‍♂️。