暗黑模式随着 iOS13 的发布开始快速走进我们的世界,到今天为止,已经相当一部分平台或者App支持暗黑模式,方便暗光环境下的使用。
在浏览器中,Chrome 从 Chrome 74 开始支持了内建的暗黑模式(Google Chrome gained a built-in dark theme on Windows in Chrome 74.),能够根据操作系统的应用主题切换暗黑模式,我们也可以方便的为网站增添支持。
纯 CSS 的模式自动切换
在不使用 JS 的前提下,使用 @media
以及 CSS 变量可以方便的为自己的网站添加支持。
使用 prefers-color-scheme
(了解 prefers-color-scheme)查询当前系统主题设置,并设置对应的 CSS 变量,可以实现 dark/light
模式之间跟随系统主题自动切换。
在使用的时候注意需要跟随主题变化的量都是用变量表示即可,这样在切换的时候就会自动使用对应主题下的变量了。
同时需要注意这个时候浏览器的自带控件并不会自己切换主题,需要我们通过 color-scheme
设置一下。
使用 CSS 的方法简单高效,能够跟随系统自动切换,但是缺点是用户不能手动切换主题。
使用 JavaScript 搭配 CSS 变量
搭配 JavaScript 可以动态的修改主题,通过往 html
/body
标签上添加或者移除 class="light"
可以实现对 :root
中定义的变量的覆盖,实现主题的切换。
我们使用搭配按钮以及 js 对 html
标签上添加 dark/light
的 class
,实现覆盖变量,主题得以切换。首先我们要获取到当前系统的主题设置,通过
来查询当前是否为暗黑模式,然后设置当前主题,使用函数 setMode
,然后我们也不希望刷新页面导致主题丢失,所以将主题名称保存在 localStorage
中。
页面加载的时候需要首先读取 localStorage
中保存的主题,如果没有再使用系统当前的主题即可。
设置完之后我们的网页就会变成这样,.dark
中的所有变量都会挂载到 html
上并且可以全局访问到。
设置自动切换
使用上面的方案会丢失自动跟随系统切换主题的功能,我们需要单独处理一下,有如下两种方法
- 借用 CSS 自己的能力,在设置为
auto
的时候,将 light/dark
样式移除,回退回默认的样式,在默认样式使用前文中的方案一,但是优先级低于 light/dark
,以保证能够覆盖样式。
- 使用 js 直接监听主题变化,并赋予对应的样式。
搭配 CSS 自动切换
在 light/dark
样式之前,添加基础样式,因为样式会在 :root
和 .dark
中复用,所以我们使用 scss
开发以实现样式复用
在主题切换设置为 auto
的时候,使用函数 clearMode
清除掉样式覆盖,让浏览器自己去决定什么主题。
使用 JS 添加事件监听
也可以直接通过事件监听直接改变样式,通过监听 prefers-color-scheme: dark
系统是否是暗黑模式实现监听。
注意看我们返回了一个函数,这个主要是方便 listener
的清除,尤其是在使用 React Hook 的时候,会频繁的创建监听,需要注意清除。
至此,我们就完成对于网站暗黑模式的支持,但是还有一些问题可以优化
- 两套样式都需要加载,如果网站较大样式较多,会占用比较多的加载事件,最好是可以动态加载。
- 目前是加载完之后再通过 js 去修改样式,如果设置主题与系统主题不一样,会出现短暂的白屏或者黑屏,还需要想办法将主题第一次设置的时机提前。