应使用 window.matchmedia('(prefers-color-scheme: dark)') 初始化判断并调用 .addeventlistener('change', ...) 监听切换,避免依赖 classlist 判断或 localstorage 缓存;css 中用 @media (prefers-color-scheme: dark) 包裹深色变量,首屏默认亮色、服务端留空主题以防止闪动;不支持环境可回退至用户手动选择或默认主题。

怎么用 prefers-color-scheme 检测系统深色模式
浏览器通过 prefers-color-scheme 媒体查询暴露用户系统偏好,不是 JS API,不能用 matchMedia 以外的方式“监听变化”——但可以监听,只是得手动写。它只返回 light 或 dark,没有 no-preference 的实际意义(现代浏览器基本忽略该值)。
常见错误是直接在 JS 里查 document.body.classList 判断主题,结果页面刚加载时没同步系统状态;或者只在初始化时查一次,后续系统切换深色模式,页面毫无反应。
- 必须用
window.matchMedia('(prefers-color-scheme: dark)')初始化判断 - 必须调用
.addEventListener('change', ...)监听切换(注意:Safari 14+、Chrome 85+ 支持,IE 不支持) - 别依赖 localStorage 缓存结果——系统偏好变了,缓存就成脏数据
CSS 里怎么写响应式深色规则才不冲突
直接覆盖原样式容易翻车:比如你写了 color: #333,又写 @media (prefers-color-scheme: dark) { color: #ddd },看似合理,但如果父元素用了 !important 或 inline style,深色规则可能被干掉。
更麻烦的是组件库自带主题(比如 Ant Design、Chakra UI),它们的深色模式通常靠 class 控制(如 dark: 前缀或 theme-dark 类),和 prefers-color-scheme 并行存在,一不留神就打架。
- 优先用
@media (prefers-color-scheme: dark)包裹整套深色变量,而不是零散改颜色 - 避免在媒体查询里用
!important——它会让后续 JS 主题切换逻辑失效 - 如果项目已用 class 控制主题(如
html[data-theme="dark"]),那就别混用媒体查询,统一入口
为什么加了 prefers-color-scheme 页面还是白屏闪动
这是最常被忽略的渲染问题:CSS 加载顺序 + JS 执行时机导致页面先按亮色渲染,再重绘为深色,肉眼可见“闪一下”。尤其在 SSR(如 Next.js、Nuxt)场景下,服务端无法读取客户端偏好,只能输出默认主题,等 JS 拿到 matchMedia 结果再改 DOM,必然闪。
不是性能问题,是渲染流水线断层。你没法靠 “优化 CSS” 解决,得从输出源头控制。
- 服务端渲染时,不要硬编码
light或dark,留空或加占位 class(如theme-pending) - 首屏关键 CSS 里,把亮色作为默认,深色规则用媒体查询包裹——这样即使 JS 没执行,样式也安全
- 避免在
useEffect或mounted里批量加 class,改用document.documentElement.classList.toggle单次操作
要不要兼容不支持 prefers-color-scheme 的旧浏览器
不用主动降级适配。CanIUse 显示 Chrome 76+/Firefox 67+/Safari 12.1+ 都已支持,iOS 13+/Android Chrome 80+ 也没问题。真正要处理的是「支持媒体查询但不支持该特性」的边缘情况,比如某些 WebView 或 Electron 旧版本。
这时候 matchMedia 可能返回 matches: false,但不代表用户不想用深色——只是查不到。强行 fallback 到亮色,体验反而更差。
- 检测时别只看
media === '(prefers-color-scheme: dark)',要检查matchMedia返回对象是否存在matches属性 - 对不支持的环境,可读取
localStorage里用户上次手动选择的主题(如果有),否则保持默认 - 别用
@supports (prefers-color-scheme: dark)包裹整个深色块——它不生效,@supports不支持媒体特性检测
深色模式不是加个媒体查询就完事,核心矛盾在于「系统偏好」「用户手动选择」「服务端上下文」三者如何对齐。最容易被忽略的,是服务端首次渲染时既不知道系统偏好,也不能阻塞 HTML 输出——这个时间差,得靠 CSS 默认态 + JS 快速接管来填平。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











