动态切换必须使用 CSS 自定义属性(如 --primary-color)配合 JS 控制,Sass 变量仅用于编译时生成 var() 语句;应统一用 map + @each 生成多主题规则,禁用硬编码值和独立变量。

动态切换 ≠ Sass 编译时替换
Sass 变量(如 $primary-color)在构建阶段就被替换成具体颜色值,比如 #007bff,浏览器运行时根本看不到它。你执行 document.documentElement.style.setProperty('--primary-color', 'red') 是对的,但写 document.documentElement.style.setProperty('$primary-color', 'red') 会报错——因为 $primary-color 这个字符串压根没进 CSS 文件,更不在 DOM 样式树里。
常见错误现象包括:
- JS 修改了某个状态变量,页面颜色完全没反应
- 用了
@if $theme == 'dark',结果编译后只有一套规则,另一套直接被删了 - 以为
vue-cli-plugin-style-resources-loader注入的 Sass 变量能响应点击事件——它只在启动时跑一次
真正能动态切换的只有 CSS 自定义属性
必须用 --primary-color 这类 CSS 变量,再配合 JS 控制:document.documentElement.setAttribute('data-theme', 'dark') 或 document.documentElement.style.setProperty('--primary-color', '#1e88e5')。所有样式都要基于 var(--primary-color) 引用,不能混用 Sass 编译出的硬编码值。
正确做法是让 Sass 只干一件事:安全生成这些 var() 语句。例如:
:root {
--color-primary: #007bff;
--color-success: #28a745;
}
[data-theme="dark"] {
--color-primary: #4dabf7;
--color-success: #4caf50;
}
这样 JS 切换 data-theme 属性,浏览器就自动重绘。Sass 的作用仅限于用 @each 遍历 $theme-colors map 输出上述规则,而不是参与运行时逻辑。
用 map + @each 生成多主题 CSS 规则
别用一堆独立变量(如 $primary-light、$primary-dark),它们无法遍历、易不同步、维护爆炸。统一收口到一个 map:
$theme-colors: ( "primary": #007bff, "success": #28a745, "warning": #ffc107 );
然后用 @each 驱动生成 :root 和 [data-theme] 规则:
:root {
@each $name, $color in $theme-colors {
--color-#{$name}: #{$color};
}
}
[data-theme="dark"] {
@each $name, $color in $theme-colors {
--color-#{$name}: #{darken($color, 10%)};
}
}
注意点:
-
#{$name}插值后是--color-primary,不是--color-"primary",map key 别加多余引号 -
darken($color, 10%)的10%是字符串,不能写成0.1,否则报错 - 对
#fff调用lighten()无效,函数内部会 clamp,结果可能不符合预期
构建时多主题打包和运行时切换是两回事
如果你需要为不同客户输出 light.css 和 dark.css,可以用 CLI 分别传参编译:sass --define=theme=light main.scss:light.css。但这和用户点按钮实时切换无关。
运行时切换必须依赖:
-
data-themeclass 或属性控制作用域 - CSS 变量 + JS 更新(
style.setProperty或setAttribute) - 所有组件样式都基于
var(--xxx),禁用任何直接引用$xxx的写法
最容易被忽略的是:Sass 编译结果里没有 @if、没有 $、也没有“条件”,只有静态 CSS;一旦忘了在源码里注释清楚哪个 map 键对应哪套 UI,半年后你自己都看不出为什么某个卡片突然变灰了。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











