css媒体查询prefers-color-scheme实现自动适配系统主题

袁志蒙 558次浏览

摘要:prefers-color-scheme 是什么?W3C 在 2020 年 7 月 31 日发布的 Media Queries Level 5 标准草案 中提到了新的属性 prefers-color-scheme,网页现在可以通过条件规则组来获取浏览器宿系统的暗色模式状态并应用了。也就是说,现在我们可以很简单地实现...

近几年,各个主流操作系统都逐渐开始重视暗色模式,从而改善用户在环境光亮低时的阅读体验。随着水果在 iOS 13 与 macOS Mojave 中添加了暗色模式,除了 Linux 以外所有的主流操作系统都已经实现了系统层级的暗色模式。Linux 由于 DE、WM 的种类繁杂暂时没有统一的标准,但目前可以通过暗色 GTK+ 主题、浏览器插件等方式实现“伪全局”暗色模式。既然有了系统层级的适配,浏览器就可以读取暗色模式开关,从而实现网页的自适应。这就是新标准 prefers-color-scheme

prefers-color-scheme 是什么

W3C 在 2020 年 7 月 31 日发布的 Media Queries Level 5 标准草案 中提到了新的属性 prefers-color-scheme,网页现在可以通过条件规则组来获取浏览器宿系统的暗色模式状态并应用了。也就是说,现在我们可以很简单地实现“暗色模式系统访问的页面是暗色的,亮色模式系统访问的页面是亮色的”。

prefers-color-scheme 有 2 种值:

light —— 浏览器宿系统使用亮色主题的界面,同时也是默认值,浏览器 privacy.resistFingerprinting 被设置为 true 时返回的也将是这个值

dark —— 浏览器宿系统使用暗色主题的界面

还有一个已废弃的值:

no-preference —— 浏览器宿系统使用未知主题的界面,当较旧版本的浏览器在宿系统不支持系统层级的暗色模式时会返回这个值,较旧版本的浏览器 privacy.resistFingerprinting 被设置为 true 时返回的也将是这个值。

@media (prefers-color-scheme: dark) {
// 暗色模式样式
}
@media not (prefers-color-scheme: dark) {
// 浅色模式样式
}

只使用 CSS 条件规则很难实现某些需求,我们可以对 window 使用 matchMedia 方法得到的 Media 使用 matches 方法来获取系统暗色模式状态:

const scheme = window.matchMedia('(prefers-color-scheme: dark)')
if (scheme.matches) {
	// 深色模式业务处理代码
	console.log('当前是深色模式');
	tipText.innerHTML = darkTip
} else {
	// 浅色模式业务处理代码
	console.log('当前是浅色模式');
	tipText.innerHTML = lightTip
}

举个例子:

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>prefers-color-scheme</title>
    <style>
        /* 整个页面配置为使用用户的配色方案首选项 */
        /* 根元素,优先级最高,与html选择器相同 */
        :root {
            --color-background: #1b1b1b;
            --color-border: #cacfd5;
            --color-text-default: #0b1016;
            --color-base: #f4f5f6;
            --color-accent: #ba0d37;
            --white-color-background: #fff;
            color-scheme: light dark;
        }
        * {
            margin: 0;
            padding: 0;
        }
        body {
            text-align: center;
            height: 100vh;
        }
        .light-scheme {
            background: var(--white-color-background);
            color: var(--color-text-default);
        }
        .dark-scheme {
            background: var(--color-background);
            color: var(--white-color-background);
        }
        h2 {
            margin: 50px auto;
            color: var(--color-accent)
        }

        /* 监听操作系统主题模式 */
        @media (prefers-color-scheme: dark) {
            body {
             color: var(--white-color-background);
                background-color: var(--color-background);
            }
        }
        @media (prefers-color-scheme: light) {
            body {
             color: var(--color-text-default);
                background-color: var(--white-color-background);
            }
        }
        .tab-type {
            display: flex;
            justify-content: center;
            padding-top: 100px;
        }
        .tab-type > li {
list-style: none;
            cursor: pointer;
            background-color: var(--color-accent);
            border-radius: 12px;
            padding: 8px 15px;
            margin: 0px 20px;
font-size: 14px;
        }
</style>
</head>

<body>
    <div id="content">
        <ul class="tab-type">
            <li id="light">浅色主题</li>
            <li id="dark">暗色主题</li>
        </ul>
        <h2>体验 prefers-color-scheme</h2>
        <div></div>
    </div>
    <script>
        // 手动修改主题颜色
        const light = document.getElementById('light')
        const dark = document.getElementById('dark')
        const content = document.getElementsByTagName('body')[0]
        const tipText = document.getElementsByClassName('scheme-tip')[0]
        let lightTip = '当前自定义主题:light亮色', darkTip = '当前自定义主题:dark暗色'

        light.onclick = function (params) {
            content.setAttribute('class', 'light-scheme')
            tipText.innerHTML = lightTip
        }
        dark.onclick = function (params) {
            content.setAttribute('class', 'dark-scheme')
            tipText.innerHTML = darkTip
        }

        // js 获取系统主题模式
        const scheme = window.matchMedia('(prefers-color-scheme: dark)')
        if (scheme.matches) {
            // 深色模式业务处理代码
            console.log('当前是深色模式');
            tipText.innerHTML = darkTip
        } else {
            // 浅色模式业务处理代码
            console.log('当前是浅色模式');
            tipText.innerHTML = lightTip
        }

        // 另外还可以实时监听系统暗色模式的状态
        window.matchMedia('(prefers-color-scheme: dark)').addListener(e => {
        if (e.matches) {
            // 系统变成了深色模式
            console.log('变成了深色模式');
            tipText.innerHTML = darkTip
        } else {
            // 系统变成了浅色模式
            console.log('变成了浅色模式');
            tipText.innerHTML = lightTip
        }
        });
</script>
</body>
</html>

当设置windows系统主题为【暗】时,网站主题会自动变化,当网站不满足系统默认主题,还想提供用户自己切换主题的功能,代码中有两个按钮,【浅色主题】和【暗色主题】就是干这件事情的。用户可以随意切换,具体切换代码可以到js部分查看,这个特性在某些场合还是比较实用的。

css媒体查询prefers-color-scheme实现自动适配系统主题css媒体查询prefers-color-scheme实现自动适配系统主题

随机内容

表情

共1条评论
  • 网友评论:

    干货满满,学习到了,感谢博主

    2023-05-15 10:49:29 回复

    点击加载