必须同时定义 light 和 dark 分支,因为 :root 未声明变量会导致浅色系统下 var(--color-bg) 回退为 unset,引发白屏或黑屏;需用 color-scheme 告诉浏览器适配原生控件。

直接用 @media (prefers-color-scheme: dark) 就能自动响应系统深色模式,但必须同时写 light 和 dark 分支,否则变量未初始化会导致页面白屏或黑屏。
为什么只写 dark 分支会出问题
常见错误是只在 @media (prefers-color-scheme: dark) 里定义颜色变量,而 :root 里没设默认值。结果在浅色系统下,--color-bg 等变量根本没声明,var(--color-bg) 回退为 unset,body 可能变成透明或继承父级黑色——尤其在 Safari 12.1+ 里表现明显。
-
:root必须先定义所有变量的浅色默认值,比如--color-bg: #fff -
@media (prefers-color-scheme: dark)仅用于覆盖,不负责“首次声明” - 别漏掉
@media (prefers-color-scheme: light)——虽然多数情况可省,但当用户系统设为no-preference时,它能兜底(Chrome/Firefox 默认按 light 渲染,Safari 不一定)
prefers-color-scheme 的兼容性与陷阱
它只在 Chrome 76+、Firefox 67+、Safari 12.1+、Edge 79+ 生效;老版本 Safari(如 12.0)会完全忽略整个媒体查询块,连里面的 CSS 规则都不解析。
- 不要嵌套复合查询,比如
@media (max-width: 768px) and (prefers-color-scheme: dark)——旧版 Safari 不识别 - 值只有
light、dark、no-preference三种,写black或night无效 - 它读的是操作系统设置,不是浏览器主题或用户手动点的开关,所以不能替代手动切换逻辑
如何让原生控件(表单、滚动条)也自动适配
光靠 @media 改背景和文字不够,<input>、<select></select>、::-webkit-scrollbar 这些默认样式不会跟着变。得加 color-scheme 告诉浏览器你支持双模式。
- 在
:root或html上加color-scheme: light dark - 这样浏览器才会在深色系统下自动把输入框边框调暗、把滚动条 thumb 染成灰色
- 局部控制也行,比如
.card { color-scheme: dark; },但全局设更省事 - 不支持该属性的浏览器会忽略它,完全不影响布局,放心用
和 Tailwind 的 dark: 修饰符混用要注意什么
Tailwind 默认用 darkMode: 'media',底层就是靠 @media (prefers-color-scheme: dark) 实现的,所以和手写 CSS 变量完全兼容。但如果你切到 class 模式(比如为了手动切换),就得停用媒体查询逻辑,否则两者冲突。
- 确认
tailwind.config.js里darkMode是'media'(默认值)还是'class' - 如果是
'class',就别再写@media (prefers-color-scheme: dark)覆盖变量,否则用户点按钮切 dark 后,系统又切回 light,CSS 变量会被媒体查询强行拉回浅色 - 混合使用时,优先级是:手动 class > media 查询 > 默认值
最易被忽略的是 no-preference 场景和原生控件适配——前者导致部分用户看到异常白/灰背景,后者让深色模式下依然弹出刺眼的白色输入框。加一行 color-scheme: light dark 和补全 light 分支,比写十行 JS 切换逻辑还管用。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











