根本原因是SCSS变量($color)属编译期占位符,CSS变量(--color)属运行时机制,二者生命周期分离;必须用#{$var}显式插值导出,且@media (prefers-color-scheme: dark)仅能在CSS中运行时生效,无法在SCSS中条件判断。

CSS在SCSS中写深色模式变量后表现不一致,根本原因不是SCSS编译错了,而是你把$color(编译期变量)和--color(运行时变量)当成一回事了——它们压根不在同一个时间、同一个系统里工作。
SCSS变量不会自动变成CSS变量
你在_variables.scss里写$primary: #3b82f6;,再写color: var(--primary);,编译后浏览器看到的仍是字面量color: var(--primary);,而--primary根本没定义。SCSS不会帮你“翻译”或“注入”CSS变量。
- 必须显式用插值语法导出:
--primary: #{$primary};,否则--primary永远不会出现在最终CSS里 -
!global只影响SCSS内部作用域,对CSS变量零作用——它不生成--xxx,也不同步值 - 如果多个SCSS文件都用
#{$primary}生成--primary,谁在编译顺序后面,谁就覆盖前面的值,这不是bug,是层叠规则生效
@media (prefers-color-scheme: dark)不能在SCSS里做条件判断
写@if (prefers-color-scheme == dark) { ... }会直接报错。SCSS是编译期工具,prefers-color-scheme是浏览器运行时根据系统设置动态计算的媒体查询条件,编译时根本不可见。
- 所有
@media (prefers-color-scheme: dark)都只能原样输出到CSS,无法参与SCSS的逻辑分支 - 试图用SCSS变量模拟主题切换(比如
$theme: dark),会导致JS手动切主题时完全失效——因为CSS变量没跟着变 - 真正可靠的切换机制是
data-theme属性:html[data-theme="dark"]+:root变量重定义,JS改属性,CSS立刻响应
Windows/macOS编译差异让变量“有时有、有时没”
同一份SCSS,在不同系统下编译出的CSS可能漏掉某些--xxx声明,常见于路径、换行符、大小写三处:
- @import路径含反斜杠(
\)时,Dart Sass在Windows下可能解析失败,导致依赖的_vars.scss没被加载,#{$color}插值为空 - CRLF(Windows)和LF(macOS/Linux)混用,会让SCSS解析器在多行map或注释后误判变量结尾,报
invalid css after "" - @use别名大小写不一致(如
@use '@/styles/Vars' as v;但文件叫_vars.scss),macOS能“蒙混过关”,Linux CI直接报Can't find stylesheet
WebView里变量全失效的真相
在iOS WKWebView或Android WebView中,window.matchMedia('(prefers-color-scheme: dark)')返回matches: false是常态,不是你的CSS有问题——是容器根本没把系统偏好透传进来。
- iOS需原生层设
webView.configuration.defaultWebpagePreferences.preferredContentMode = .recommended - Android 10+需调用
WebSettings.setForceDark(WebSettings.FORCE_DARK_ON) - 没有原生配置,
@media (prefers-color-scheme: dark)规则永远不匹配,:root里的暗色变量也不会生效
最易被忽略的一点:所有var(--x)必须带fallback,比如color: var(--text, #333);。一旦变量未定义(编译遗漏、WebView未透传、JS未初始化),没fallback就会回退到透明或不可控的浏览器默认值,而不是“沿用浅色”。这不是容错问题,是渲染链上必填的一环。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











