scss变量与css变量本质不同:前者是编译期静态常量(用$定义,编译后消失),后者是运行时动态属性(用--定义,保留在css中供js操作和继承);二者生命周期、作用域及使用方式均无交集。

SCSS变量和CSS变量根本不是一回事
很多人卡在第一步:以为 $color-primary 和 --color-primary 是同一个东西的两种写法。它们完全独立——SCSS变量只存在于编译前,生成的是静态CSS;CSS变量在浏览器里运行时才起作用。你在SCSS里写 $color: red !global,不会自动创建或修改任何 --color。编译后,它只是个颜色值,比如 color: #f00,跟 var(--color) 没半点关系。
常见错误现象:
- 写了
$primary: #3b82f6 !global,但button { color: var(--primary); }依然用的是旧值——因为压根没定义--primary这个CSS变量 - 试图在
@mixin里改$color !global,然后期望按钮背景色响应式变化——不行,SCSS不参与运行时逻辑
覆盖CSS变量靠层叠,不是靠!global
CSS变量的“局部覆盖”,本质是利用选择器优先级和继承链。你不需要、也不应该用SCSS去“同步”它。
正确做法是直接在目标选择器里重声明同名 -- 变量:
- 全局基础值写在
:root里::root { --color-primary: #3b82f6; } - 想让某个卡片用深色主题?加一个更具体的选择器:
.card-dark { --color-primary: #1e40af; } - 确保HTML结构中该卡片元素被
class="card-dark"包裹,子元素调用var(--color-primary)就会自动取新值 - 按钮单独换色?直接写:
button.special { --color-primary: #ef4444; },不用动任何SCSS变量
!global只影响SCSS编译期作用域
!global 的唯一任务,是在SCSS文件内把一个局部声明的 $ 变量提升为全文件可见。它不跨文件、不跨模块、不碰CSS变量。
典型误用场景:
- 在
@media块里写$breakpoint: "lg" !global,以为能实现“响应式变量”——实际只是把最后一次赋值的结果固化下来,和媒体查询行为无关 - 在
@use模块化项目中滥用!global,结果变量无法被其他模块访问(@use "x" as *也不行,必须显式@use "x"并通过命名空间引用) - 重复声明同名全局变量:
$theme: "dark" !global再来一次,会报错Invalid CSS after "$theme": expected "{", was "!global"
真正需要动态CSS变量时该怎么做
如果目标是运行时可变的主题色(比如用户切换深色模式),SCSS无能为力,得靠JS或纯CSS方案。
推荐路径:
- 用
:root定义默认值,再用@media (prefers-color-scheme: dark)覆盖:@media (prefers-color-scheme: dark) { :root { --color-primary: #1e40af; } } - 用JS动态切换类名:
document.documentElement.classList.add("theme-dark"),配合.theme-dark { --color-primary: #1e40af; } - 避免在SCSS里做“变量映射”:
$primary: #3b82f6; :root { --primary: #{$primary}; }看似聪明,但失去CSS变量的运行时灵活性,且增加维护成本
最容易被忽略的一点:CSS变量的遮蔽(shadowing)发生在渲染树上,不是源码层级。哪怕你在多个嵌套选择器里反复声明 --x,浏览器只认离目标元素最近的那个有效声明——这和SCSS变量的作用域模型毫无相似性。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











