为什么CSS在Sass中自动生成主题色后无法动态切换?

作者:袖梨 2026-09-01

SCSS变量在构建阶段即被替换为固定值,无法运行时修改;CSS变量(如--primary-color)是浏览器原生支持的运行时属性,可通过JS动态读写并实时重绘。

浏览器根本没见过 $primary-color

Sass 变量在构建阶段就被替换成具体颜色值,比如 $primary-color: #409eff 编译后直接变成 color: #409eff;。浏览器加载的 CSS 文件里没有任何 $ 符号,document.documentElement.style.setProperty('$primary-color', 'red') 会报错,getComputedStyle() 也查不到它——它压根没进运行时环境。

@if $theme == 'dark' 不会响应用户点击

@if 是编译期指令,只在你执行 sass 命令或启动 Vite/Webpack 时运行一次。此时 document 还不存在,localStorageprefers-color-scheme、按钮点击事件全不可见。常见错误包括:

  1. 写了 $theme: 'dark' 后在组件里改 JS 状态,但样式毫无变化
  2. vue-cli-plugin-style-resources-loader 注入变量,误以为能动态更新
  3. 期望 Sass 编译出带逻辑分支的 CSS,实际输出里只有被选中的那部分规则,其余被彻底丢弃

真正能切换的只有 CSS 自定义属性

动态主题必须靠 --primary-color 这类 CSS 变量 + JS 控制,例如:

document.documentElement.style.setProperty('--primary-color', '#1e88e5');

所有样式都得基于 var(--primary-color) 引用,不能混用 Sass 变量值。否则会出现“JS 改了变量,页面颜色卡在编译那一刻”的典型现象。Sass 的作用仅限于安全生成这些 var() 语句,比如用 @each 遍历 $theme-colors map 输出完整的 :root 规则。

多主题打包和运行时切换是两回事

如果你需要为不同客户输出独立 CSS 文件(如 light.cssdark.css),可以用 CLI 分别传参编译:sass --define=theme=light main.scss:light.css。但这和用户点按钮实时切换无关——后者必须依赖 data-theme class 或 CSS 变量 + JS 更新。最容易被忽略的是:Sass 编译结果里没有 @if、没有 $、也没有“条件”,只有静态 CSS;一旦忘了在源码里注释清楚哪个 map 键对应哪套 UI,半年后你自己都看不出为什么某个卡片突然变灰了。

相关文章

精彩推荐