正确做法是将:root规则整体包裹在@media (prefers-color-scheme)中;CSS变量作用域由声明位置决定,媒体查询内无法覆盖:root顶层同名变量;fallback值不响应深色模式切换。

prefers-color-scheme媒体查询必须写在:root外层
直接在:root里用@media (prefers-color-scheme: dark)嵌套定义变量是无效的——CSS变量作用域由声明位置决定,而@media块内无法覆盖:root顶层作用域的同名变量(除非显式重申:root)。正确做法是把整个:root规则包进媒体查询里:
/* ✅ 正确:媒体查询包裹 :root */
@media (prefers-color-scheme: light) {
:root {
--bg: #ffffff;
--text: #333333;
}
}
@media (prefers-color-scheme: dark) {
:root {
--bg: #121212;
--text: #f0f0f0;
}
}
这样浏览器会根据系统偏好加载对应的一组:root变量,后续所有var(--bg)都能自动响应。
变量默认值不能替代媒体查询逻辑
var(--color, #000)里的 fallback 值只在变量未定义时生效,它**不感知深色模式切换**。比如你只在:root里定义了--bg,又在@media (dark)里改写了它,那var(--bg, #fff)永远取不到#fff——因为--bg始终是已定义状态。
- fallback 适合兜底「变量可能压根没声明」的场景,比如第三方组件未注入主题变量
- 深色/浅色适配必须靠
@media (prefers-color-scheme)主动声明两套值 - 若想降级到系统未支持该特性时的默认样式,需额外加一层
@supports not (prefers-color-scheme: dark)
JavaScript读取和修改需注意计算时机
用getComputedStyle(document.documentElement).getPropertyValue('--bg')读取时,返回的是当前已生效的值(即匹配媒体查询后的结果);但用document.documentElement.style.setProperty('--bg', '...')设置时,会覆盖媒体查询定义的值,且**不会自动回退**——哪怕用户之后切回浅色模式,这个JS设置的值仍保持不变。
- 动态主题切换建议用 class 切换(如
document.body.classList.toggle('dark-theme')),配合 CSS 中.dark-theme :root定义变量,更可控 - 若必须用 JS 设置,记得监听
prefers-color-scheme变化:window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', ...) - Safari 15.4+ 才完全支持
matchMedia对prefers-color-scheme的监听,旧版需降级处理
变量继承与局部覆盖要小心层级陷阱
深色模式变量常被放在:root,但如果你在某个组件里写了.card { --bg: #1e1e1e; },那么.card div { background-color: var(--bg); }会取这个局部值,而非:root里媒体查询定义的--bg。这本身是正常行为,但容易误判「为什么深色模式没生效」。
- 检查是否意外在父元素上重新声明了同名变量
- 用浏览器开发者工具的「Computed」面板点开
background-color,看右侧var(--bg)最终解析成什么值,再点进去查--bg来源 - 避免在
:root外重复定义核心主题变量,统一收口管理
真正麻烦的不是写法,而是变量被多层覆盖后,你得一层层往上翻计算链——尤其当团队协作、组件库混用时,--bg到底是谁定义的,往往得靠调试器现查。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











