根本原因是变量未在:root中预定义初始值、媒体查询块顺序靠前被后续样式覆盖、或var()调用缺少合法fallback;必须确保:root先声明所有变量默认值,@media块置于末尾完整覆盖,且每个var()都带fallback。

为什么直接用 prefers-color-scheme 重定义变量有时不反转主题色
常见现象是加了 @media (prefers-color-scheme: dark) { :root { --bg: #121212; } },但部分按钮或文字颜色还是亮的。根本原因不是媒体查询没生效,而是:变量被更早定义的规则覆盖、:root 里没声明初始值、或者组件样式里漏写了回退值导致 var(--bg) 解析失败后取浏览器默认色(比如白色背景上黑色文字,暗色下仍为黑字)。
必须确保三件事同时成立:亮色变量在 :root 中有初始声明;暗色媒体查询块写在所有其他 :root 声明之后;所有 var() 调用都带合法回退值。
:root 中必须预设亮色变量,不能只靠媒体查询“补全”
浏览器解析 CSS 是顺序执行的。@media 块里的变量声明不会“补充”未定义的变量,只会覆盖已存在的同名变量。如果 :root 里压根没写 --text-primary,那暗色媒体查询再怎么重写也无效——因为变量从未存在过。
正确写法是:
立即学习“前端免费学习笔记(深入)”;
:root {
--text-primary: #111;
--bg-surface: #fff;
--border: #e0e0e0;
}
@media (prefers-color-scheme: dark) {
:root {
--text-primary: #eee;
--bg-surface: #121212;
--border: #333;
}
}
关键点:
- 所有变量必须在普通
:root块中首次声明,哪怕只是占位值 - 暗色媒体查询必须放在后面,否则层叠顺序导致覆盖失败
- 避免在
.dark类里重复定义整套变量——那会和prefers-color-scheme冲突,且无法自动响应系统切换
主题色反转 ≠ 全部取反,得按语义分层控制
把 --primary 从蓝色改成深蓝、--error 从红色改成酒红,这叫适配,不是反转。真正需要“反转”的通常是中性色:--text-default、--bg-base、--surface 等。而品牌色如 --primary 应保持视觉一致性,仅微调饱和度或明度。
容易踩的坑:
- 给
--primary写var(--primary, #007bff),结果暗色下它还是亮蓝,和深灰背景对比度过低 - 误以为
color-mix(in srgb, black 30%, var(--primary))能自动适配,但该函数不支持变量嵌套,var(--primary)会被当作字符串处理 - 用
filter: invert(1)强制反转图片或图标,但会把 logo 颜色也翻转,破坏品牌识别
推荐做法:为中性色单独建一组变量,例如 --text-on-light / --text-on-dark,再用 color: var(--text-on-light, #333); + 媒体查询切换它们的值。
JS 手动切换时,data-theme 和 prefers-color-scheme 如何共存
用户点了“深色模式”按钮,但系统偏好是亮色,这时候该以谁为准?答案是:JS 切换优先级高于媒体查询。但实现上不能简单删掉媒体查询块,而要让两者协同。
核心逻辑:
- 用
document.documentElement.setAttribute('data-theme', 'dark')设置主动选择 - CSS 中写
[data-theme="dark"] :root覆盖变量,且该选择器权重高于@media块 - 同时保留
@media (prefers-color-scheme: dark) { :root:not([data-theme]) { ... } }作为 fallback - 初始化时读取
localStorage,若无记录再查matchMedia,避免页面闪动
典型错误:[data-theme="dark"] 选择器写成 [data-theme="theme-dark"],导致 JS 设置的值和 CSS 不匹配,变量完全不生效。
最易被忽略的是变量作用域链:CSS 自定义属性不继承,只靠层叠。哪怕你把 --text-primary 写在 body 上,子元素用 var(--text-primary) 也拿不到——必须挂在 :root 或明确祖先选择器里。调试时直接打开 DevTools 的 Computed 面板,搜 var(--xxx),看它解析出的实际值和来源,比猜快得多。


















