prefers-color-scheme 是 css 媒体查询,用于声明式响应系统暗黑/亮色偏好,无需 javascript;需配合 data-theme 属性实现手动切换与持久化,避免刷新丢失和闪屏。

如何用 prefers-color-scheme 检测系统主题
浏览器原生支持通过 CSS 媒体查询检测用户系统偏好,无需 JavaScript 就能响应暗黑/亮色切换。关键不是“监听”,而是“声明式适配”——@media (prefers-color-scheme: dark) 会自动生效,只要系统设置变更且页面未被缓存强制锁定主题。
常见错误是只写 @media (prefers-color-scheme: dark) 却漏掉亮色回退样式,导致暗黑模式下部分元素没定义颜色而发灰或不可读。正确做法是:基础样式按亮色写,再用媒体查询覆盖暗色变量。
- Windows/macOS/iOS/Android 系统级深色开关开启后,该媒体查询立即生效(无需刷新)
- Safari 12.1+、Chrome 76+、Firefox 96+ 均支持,Edge 基于 Chromium 后也支持
- 不支持的旧浏览器会直接忽略该媒体查询,按默认样式渲染(即亮色)
为什么不能只靠 prefers-color-scheme 实现手动切换
它只反映系统偏好,无法覆盖用户主动点击“切换主题”按钮的行为。一旦你加了手动开关,就必须脱离纯 CSS 响应逻辑,引入状态管理——否则用户点了“切暗黑”,系统却是亮色,下次刷新就打回原形。
核心矛盾在于:prefers-color-scheme 是只读信号,不是可写状态。手动切换必须落地为 DOM 层级控制(如给 加 data-theme="dark"),再用 CSS 优先级压制系统查询结果。
- 推荐策略:用
data-theme属性作为唯一可信源,CSS 中写[data-theme="dark"] { ... }和@media (prefers-color-scheme: dark) [data-theme="auto"] { ... } - 初始化时读取
window.matchMedia('(prefers-color-scheme: dark)').matches设置初始data-theme - 避免同时用 class 和 attribute 控制主题,容易冲突;统一用
data-theme
matchMedia 监听变化时容易漏掉的边界情况
matchMedia 的 addEventListener(或旧版 addListener)确实能捕获系统主题变更,但有三个实际项目中高频出问题的点:
- 页面加载完成前系统已切换主题,此时
matchMedia().matches已是新值,但监听器尚未绑定 → 必须在绑定前先执行一次初始化逻辑 - 移动端 Safari 在后台标签页切回前台时,可能不会触发 change 事件 → 需配合
visibilitychange事件做兜底检查 - 某些 Android WebView(尤其旧版)不触发 change → 要 fallback 到定时轮询(如每 5 秒查一次
matches,仅限 WebView 场景)
示例关键片段:
const media = window.matchMedia('(prefers-color-scheme: dark)');
function updateTheme() {
document.documentElement.setAttribute('data-theme', media.matches ? 'dark' : 'light');
}
updateTheme(); // 先执行一次
media.addEventListener('change', updateTheme);
CSS 变量与主题切换的性能和兼容性取舍
用 CSS 自定义属性(--bg-color 等)管理主题色最灵活,但要注意两点硬限制:
- CSS 变量本身不触发重排,但大量使用
var(--color)替代硬编码值,在低端安卓机上可能增加样式计算耗时(尤其嵌套多层calc()时) - IE 完全不支持 CSS 变量 → 如果需兼容 IE,必须用 class 切换 + 预设整套规则,或用 PostCSS 插件编译出降级方案
- 不要在
@keyframes里用 CSS 变量做动画颜色 —— 大部分浏览器不支持动画中动态响应变量变更
真正省事又稳妥的做法:亮色用默认值,暗色用 [data-theme="dark"] 下的变量覆盖,所有组件都继承自根节点,避免每个组件单独写 media 查询。
localStorage,导致刷新即丢失;以及服务端渲染(SSR)场景下,首屏 HTML 没带正确的 data-theme,造成闪屏。这两处必须显式处理。前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











