随着深色模式越来越流行,微信、知乎、各种操作系统等等都提供了深色主题。细心的朋友也许会发现,很多网站都已经可以根据用户当前的系统主题自动使用对应配色了,甚至当用户切换系统主题的同时,这些网站也能同步切换。

2019年7月30日,Chrome 发布了 76 版本,标志着 prefers-color-scheme 被大部分的现代浏览器所支持。

prefers-color-scheme 是一种媒体特征(Media Feature),在媒体查询(Media Query)中使用,用于检测用户是否有要求浏览器使用浅色(light)或者深色(dark)模式。

该特征只有 2 种可能的值:darklight

因此,我们可以这样设置颜色:

/* 深色模式 */
@media (prefers-color-scheme: dark) {
    body {
        background-color: black;
    }
}
/* 浅色模式 */
@media (prefers-color-scheme: light) {
    body {
        background-color: white;
    }
}

这样设置会导致网站主题随着用户系统主题的改变而改变,如果使用场景需要允许用户自定义主题,那么单用 CSS 来控制就不够了,还需要配合 Javascript。

那么 js 如何获取媒体查询的结果呢?

在 window 对象中有这样一个方法:matchMedia,几乎所有浏览都支持它,可以放心的使用。这个方法只接受一个参数,就是媒体查询的字符串,并返回一个 MediaQueryList 对象实例。该对象有只有 3 个属性:

  1. media:媒体查询,等于传入的参数。
  2. matches:布尔值,表示查询结果正确与否。
  3. onchange:null,允许开发者传入一个回调函数,当媒体查询的结果改变时就会被触发。
// 本例通过设置 body 的 classname 来控制主题颜色
const mql = window.matchMedia('(prefers-color-scheme: dark)');
if (mql.matches) {
    // 当前为深色模式
    document.body.classList.add('dark-mode');
} else {
    // 当前为浅色模式
    document.body.classList.remove('dark-mode');
}

如果需要可以根据系统主题的改变而自动切换模式的功能,那么就可以设置 onchange 事件的回调函数,当媒体查询结果改变时,回调函数就会被触发,可以在函数内部进行主题切换。​

// 当设置要根据系统主题自动切换模式,执行以下代码
const mql = window.matchMedia('(prefers-color-scheme: dark)');
// 设置 onchange 事件的回调函数
mql.onchange = function (evt) {
    if (evt.matches) {
        // 当前为深色模式
        document.body.parentElement.classList.add('dark-mode');
    } else {
        // 当前为浅色模式
        document.body.parentElement.classList.remove('dark-mode');
    }
}

再配合一键全站切换深色模式的魔法代码,即可快速实现根据系统主题选择用浅色还是深色模式的功能。

/* 魔法代码:一键全站切换深色模式 */
html.dark-mode {
    filter: invert(1) hue-rotate(180deg);
}

(完)