css原生变量是实现动态主题的唯一方案,因其可在运行时被javascript实时修改并触发重绘,而sass变量仅在编译期存在,无法响应用户交互或系统偏好变化。

CSS原生变量存颜色,不是“更好”,而是“唯一能做动态主题的事”——Sass函数根本没机会参与运行时逻辑。
var(--primary-color)能被JavaScript实时修改,$primary-color在打包后就消失了
浏览器里真实存在 --primary-color 这个属性,调用 document.documentElement.style.setProperty('--primary-color', '#121212') 后,所有 background-color: var(--primary-color) 的元素下一帧就会重绘;而 $primary-color 只是 Sass 编译器内部的文本占位符,输出的 CSS 文件里搜不到它,setProperty('$primary-color', ...) 会直接抛 InvalidPropertyError。
常见错误现象:
- Vue 组件中写
:style="{ '--bg': themeBg }",但themeBg来自$bg——绑定的是编译时的死值,状态变了颜色纹丝不动 - 想用
getComputedStyle(el).getPropertyValue('--text')拿当前主题文字色,结果发现$text根本没有这个 API
深色模式切换必须走CSS变量,Sass做不到响应式更新
Sass 变量只在构建阶段生效,无法感知 prefers-color-scheme 或用户点击切换按钮这类运行时事件。
正确做法是:
- 在
@media (prefers-color-scheme: dark)里用:root { --text: #eee; }动态覆盖 - 手动切换时调用
document.documentElement.style.setProperty('--text', '#121212') - 不要试图用
@if $dark-mode { ... }输出两套 CSS——那只是静态分支,不响应变化
如果你的“深色模式”靠换 <link> 标签或重载整个 CSS 文件,说明你还没真正用上 CSS 变量的能力。
颜色函数(如 lighten/darken)不能用在 var() 里,但也不该用在 CSS 变量场景
lighten(--primary, 10%) 是非法语法,CSS 里没有这种函数;Sass 的 lighten($primary, 10%) 是编译期计算,输出固定值,比如 #4a90e2。
所以实际方案是:
- 把常用变体提前算好:定义
--primary-light、--primary-dark等变量,由 JS 控制开关 - 或者用 CSS
color-mix()(Chrome 111+)、oklch()等新函数做运行时混合,但兼容性需兜底 - 别指望用
var(--primary)去喂 Sass 函数——它们不在同一个时空里
scoped样式里写 :root 会失效,这是 Vue/React 开发者最常踩的坑
在 <style scoped></style> 中写 :root { --color: red },Vue 会自动加上属性选择器变成 :root[data-v-xxx] { --color: red },破坏了 :root 的全局语义,变量不会生效。
正确做法只有两个:
- 把全局变量定义写在未加
scoped的<style></style>块里(推荐) - 或用
<style></style>外链一个纯 CSS 文件,里面定义:root
这个坑不报错、不警告,只默默让主题色不生效——调试时容易绕远路。
真正关键的分界点从来不是“哪个更高级”,而是“谁在运行时还活着”。--color 活着,$color 死了。你要控制的如果是用户点击、系统偏好、网络状态这些变量,答案只有一个:用原生变量,别犹豫。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











