SCSS无法在编译时响应prefers-color-scheme,只能原样输出媒体查询;正确做法是用map统一管理主题变量,先声明:root默认值,再用@media覆盖,并配合color-scheme: light dark和JS手动同步变量。

SCSS里不能直接用@media (prefers-color-scheme: dark)嵌套生成变量
很多人在 SCSS 中写 @media (prefers-color-scheme: dark) { :root { --bg: #121212; } },以为能“编译出两套 CSS”,但这是错的——SCSS 是编译时工具,@media (prefers-color-scheme: dark) 是运行时浏览器行为,SCSS 不会、也不能提前模拟系统偏好。它只会原样输出该媒体查询,不生成额外逻辑。
真正要做的,是让 SCSS 帮你**安全组织变量结构**,而不是试图让它“响应”系统。常见错误包括:
- 在
@media块里定义新变量名(如--bg-dark-only),导致浅色模式下var(--bg-dark-only)读不到值,回退失效 - 把
@media嵌套在@mixin或@if里,结果编译后媒体查询被破坏或丢失 - 依赖 SCSS 的
$variable在不同媒体查询中“自动切换”,但 CSS 变量必须靠运行时覆盖,SCSS 变量只存在于编译前
:root 中必须先声明默认值,再用 SCSS 输出媒体查询覆盖
SCSS 的价值在于避免手写重复的 :root 声明。你应该用一个 map 统一管理主题 token,再用循环输出两套规则:
$theme-tokens: (
bg-base: (#fff, #121212),
text-primary: (#333, #eee),
border: (#ddd, #333)
);
:root {
@each $name, $values in $theme-tokens {
--#{$name}: nth($values, 1);
}
}
@media (prefers-color-scheme: dark) {
:root {
@each $name, $values in $theme-tokens {
--#{$name}: nth($values, 2);
}
}
}
这样生成的 CSS 是干净、可预测的。关键点:
- 所有变量名(如
--bg-base)必须在顶层:root先初始化,否则未匹配媒体查询时var(--bg-base)会 fallback 到initial或浏览器默认(常是白底黑字) - 不要用
!default混淆作用域:SCSS 的$var: value !default和 CSS 的var(--x, fallback)完全无关 - 别在 SCSS 中写
@media (prefers-color-scheme: light)—— 它冗余,且和默认样式重复;只需确保默认值就是 light 态
color-scheme: light dark 必须显式加在 html 上
仅靠 CSS 变量改背景和文字颜色,对 <input>、<select></select>、滚动条、SVG 填充等完全无效。这些元素依赖浏览器 UA 样式,而 UA 样式是否启用深色语义色,取决于 html { color-scheme: light dark; } 声明。
这个声明不能漏,也不能写在媒体查询里(它本身不是条件样式):
html {
color-scheme: light dark;
}
它告诉浏览器:“我支持两种系统配色方案,请按需渲染原生控件”。没有它:
- iOS Safari 会强制用浅色表单,哪怕系统设了深色
- 某些安卓 WebView(如微信内置浏览器)会忽略
prefers-color-scheme媒体查询 - 滚动条 thumb、track 颜色不会自动变,得手动用
::-webkit-scrollbar覆盖(但优先级低于color-scheme)
SCSS 无法替代 JS 实现用户手动切换
如果你加了个“切换主题”按钮,只靠 SCSS + @media (prefers-color-scheme: dark) 是没用的。因为用户点击时,系统偏好可能仍是 light,媒体查询根本不会触发。
此时 SCSS 唯一能帮上忙的,是提供一套与 JS 同步的变量结构。比如:
- JS 切换时调用
document.documentElement.style.setProperty('--bg-base', '#121212') - SCSS 里所有组件样式都用
var(--bg-base),不硬编码颜色 - 同时保留媒体查询作为首次加载的 fallback,但不指望它响应按钮点击
最容易被忽略的是:**媒体查询和 JS 设置的变量必须共用同一套变量名,且 JS 设置必须在 DOM ready 后立即执行,否则页面会闪一次系统默认色再跳变**。这个时机差,比写错 SCSS 还容易导致视觉 bug。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











