SCSS变量编译后消失,仅在构建期生效;CSS变量是运行时真实存在的自定义属性,支持JS动态读写和响应式更新。两者能力边界分明:Sass处理编译逻辑,CSS变量负责运行时主题切换。

SCSS变量编译后就消失了,浏览器根本看不到
你在.scss里写$primary: #4285f4,Sass编译器会把它所有出现位置替换成#4285f4,最终生成的CSS文件里搜不到$primary这三个字符。浏览器加载的是这个编译后的CSS,DOM里没有$primary这个东西,document.documentElement.style.setProperty('$primary', 'red')直接报错:InvalidPropertyError。
常见错误现象:
- 改了
uni.scss里的$uni-color-primary,重新编译才生效,运行时调用uni.setStorageSync('theme', 'dark')页面毫无反应 - 在Vue组件
<style scoped>里写$bg: v-bind(themeBg)——Sass根本不解析JS表达式,这行被当作文本忽略或报错 - 控制台执行
getComputedStyle(document.documentElement).getPropertyValue('$primary')返回空字符串
CSS变量是真实存在的CSS属性,JS能读能写能触发重绘
--primary-color是浏览器原生支持的自定义属性,注册在CSSOM中,和color、font-size一样是“活”的。你调用document.documentElement.style.setProperty('--primary-color', '#121212'),所有var(--primary-color)引用的地方立刻响应,过渡动画照常执行,不需要刷新、不中断渲染流程。
必须注意的实操细节:
立即学习“前端免费学习笔记(深入)”;
- 修改必须走
document.documentElement,不是document.body——否则后代元素可能拿不到继承值 -
:root { --primary: #{$primary}; }是合法写法(Sass编译时展开),但:root { --primary: $primary; }会输出字面量$primary,浏览器当无效值丢弃 - Vue/React中写
:style="{ '--bg': themeBg }"是对的,前提是CSS里用的是var(--bg),不是$bg
两者能力边界完全不同,不能互相模拟
Sass变量擅长编译期逻辑:条件分支@if $theme == 'dark'、颜色函数lighten($primary, 10%)、循环生成断点;CSS变量只负责运行时传递,不支持if、不支持lighten()、不能参与@media条件判断。
典型混用陷阱:
- 想用
calc(var(--gap) * 2)替代$gap * 2——必须写成calc(var(--gap) * 2),var(--gap) * 2整条声明会被浏览器忽略 - 以为
--spacing能像$spacing一样在@keyframes里参与计算——不行,CSS变量在@keyframes中只能作为静态值引用 - 在
<style scoped>里写:root { --x: y }——scoped会加属性选择器,破坏:root匹配,变量不生效
主题切换必须靠CSS变量,SCSS只能做前期准备
用户点击切换深色模式,毫秒级响应依赖的是setProperty注入新值,而不是加载dark.css。后者会引发FOUC(闪白)、缓存失效、transition中断。SCSS唯一能做的,是在构建阶段把设计令牌(颜色、间距等)通过--primary: #{$primary}这类写法,批量注入到:root中,为运行时切换提供初始值。
真正容易被忽略的是作用域层级:
- 改一个
--color可能影响几十个组件,因为它是按CSS层叠规则继承的 - 改一个
$color只影响当前文件编译结果,这是设计使然,不是缺陷 - 不要在项目里同时维护
$theme和--theme两套系统,值不同步是必然的


















