@media (prefers-color-scheme: dark) 不生效主因是环境不支持或写法错误:系统未开启深色模式、file://协议下被禁用、语法错误(如用等号)、规则位置靠前被覆盖,或浏览器版本过低(Safari 12.1+/Chrome 76+才支持)。

直接用 @media (prefers-color-scheme: dark) 就能检测,不需要 JS —— 但只在支持的浏览器里生效,且必须写对语法、放对位置,否则永远不触发。
为什么写了 @media (prefers-color-scheme: dark) 却没反应
绝大多数“检测失败”不是代码逻辑问题,而是环境或写法踩坑:
- 系统根本没开深色模式:macOS 要进「系统设置 → 外观」选“深色”,Windows 是「设置 → 个性化 → 颜色 → 默认应用模式」设为“暗色”
- 在本地双击打开 HTML(
file://协议):Safari 和部分安卓 WebView 会禁用该媒体查询,必须起本地服务测试(比如python3 -m http.server) - CSS 文件未加载或有语法错误:打开开发者工具的「Styles」面板,看这条规则是否显示为灰色(表示未匹配)
- 写成了
@media (prefers-color-scheme = dark)或@media (prefers-dark-mode):等号是错的,prefers-dark-mode根本不存在 - 规则写在默认样式之前:CSS 是顺序覆盖的,
@media必须放在基础样式之后,否则不会生效
window.matchMedia('(prefers-color-scheme: dark)') 怎么用才可靠
这是 JS 中唯一合法读取系统偏好值的方式,但它本身不“监听”,只是快照。要响应系统切换,必须手动绑定事件:
- 读当前值:
window.matchMedia('(prefers-color-scheme: dark)').matches返回true或false - 监听变化(关键!):
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', handler)—— 漏掉addEventListener,系统切主题后页面不会更新 - 别在初始化时只查一次就完事:用户可能开着页面改系统设置,不监听 change 就永远卡在旧状态
- 注意 Safari 12.1+、Chrome 76+、Firefox 67+ 才支持;IE 完全不识别,加了也白加
怎么让深色检测和手动切换不打架
系统检测和用户点击“切换”是两套逻辑,冲突时必须明确优先级。推荐用 data-theme 统一控制:
立即学习“前端免费学习笔记(深入)”;
- 初始加载时:先读
localStorage.getItem('theme'),有值就用它;没有就 fallback 到window.matchMedia的结果 - 用户点按钮后:存到
localStorage(别用sessionStorage),同时设document.documentElement.dataset.theme = 'dark'或'light' - 系统变化时(
change事件):只在data-theme === 'auto'时才更新 DOM,避免覆盖用户手动选择 - CSS 里按优先级写:
[data-theme="dark"]规则必须比:root和@media更具体,否则手动切换无效
真正容易被忽略的是:prefers-color-scheme 是被动信号,它不触发重绘,也不保证实时——有些旧版 Safari 在系统切换后要 resize 窗口才会重新计算媒体查询。所以监听 + localStorage + data-theme 三者缺一不可,单靠 CSS 媒体查询只够应付最基础场景。



















