scss变量($xxx)是编译期静态值,仅在sass编译时替换为具体值,不参与运行时级联;css变量(--xxx)是运行时动态实体,可继承、覆盖、被javascript读写,适用于主题切换等场景。

SCSS变量和CSS变量别混用
SCSS变量($color-primary)在编译时就被替换成具体值,不参与运行时级联;而CSS变量(--color-primary)才是真正的“可级联、可覆盖、可继承”的动态实体。想靠SCSS变量实现主题切换或响应式覆盖,本质上走不通——它压根不会出现在最终CSS里。
常见错误现象:$theme-color: #007bff; 写在 _variables.scss 里,然后在组件中又写 $theme-color: #dc3545;,结果发现样式没变——因为这是两个独立的编译期局部变量,彼此无关联,更不构成“覆盖”。
- SCSS变量作用域只取决于声明位置:在规则块外是全局(文件级),在选择器内是局部(仅该块生效)
- SCSS变量无法被JavaScript读取或修改,也不能用
var(--x)引用 - 真正需要级联覆盖的场景,必须用CSS变量,SCSS只负责生成它们的初始值或批量声明
用SCSS批量生成CSS变量并注入:root
把SCSS当“模板引擎”来用:用$变量定义设计系统原始值,再用循环/映射批量输出--变量到:root,这样既保留SCSS的维护性,又获得CSS变量的运行时能力。
@use "sass:map";
<p>$colors: (
"primary": #007bff,
"success": #28a745,
"warning": #ffc107
);</p><p>:root {
@each $name, $value in $colors {
--color-#{$name}: #{$value};
}
}</p>
这样生成的CSS里会有 --color-primary: #007bff 等真实CSS变量,后续可在任意地方用 var(--color-primary) 引用,并支持JavaScript动态修改 document.documentElement.style.setProperty('--color-primary', 'red')。
- 不要在SCSS中直接写
--color-x: $value(语法错误),必须用插值--color-#{$name}: #{$value} - 如果项目有深色主题,可额外定义
$colors-dark映射,配合.dark-theme类批量注入另一套值 - 注意:SCSS生成的
:root变量仍受CSS优先级约束,后续同名:root声明会覆盖前面的
在组件级用CSS变量覆盖全局值
CSS变量天然支持局部覆盖,关键在于作用域层级是否正确。不是“在SCSS里改$变量”,而是“在组件选择器里声明同名--变量”。
例如全局定义了 :root { --spacing-unit: 8px; },某个卡片组件想用更大间距:
.card {
--spacing-unit: 16px; /* ✅ 覆盖生效 */
padding: var(--spacing-unit);
}
<p>.card .header {
margin-bottom: var(--spacing-unit); /<em> 拿到的是16px,不是8px </em>/
}</p>
这个覆盖完全由CSS引擎在运行时完成,和SCSS无关。SCSS此时只适合做辅助:比如把.card的--spacing-unit值也从$card-spacing变量派生,保持设计系统一致性。
- 覆盖只对当前选择器及其后代生效,
.card外的元素仍用:root里的8px - 避免在深层嵌套选择器里反复声明同一
--变量,容易失控;优先在组件根选择器上统一声明 - 调试时用浏览器开发者工具检查
Computed面板,看var(--x)最终解析成什么值,比猜更可靠
JavaScript读写CSS变量时的坑
用JS操作CSS变量时,常因作用域理解偏差导致读不到或写不对。核心原则:读写目标必须与变量声明的作用域匹配。
比如变量在:root声明,就必须用document.documentElement;若在.modal里声明,就得用modalEl实例。
// ✅ 正确:读全局变量
const root = document.documentElement;
const primary = getComputedStyle(root).getPropertyValue('--color-primary').trim();
<p>// ❌ 错误:试图从body读全局变量(body不声明,只继承)
const body = document.body;
const primaryWrong = getComputedStyle(body).getPropertyValue('--color-primary'); // 可能为空字符串</p><p>// ✅ 正确:写局部变量
const card = document.querySelector('.card');
card.style.setProperty('--spacing-unit', '24px');</p>
-
getComputedStyle()返回的是计算后值,但对var()引用只返回原始字符串(如"var(--color-primary)"),需用getPropertyValue取原始声明值 - 写入时,
style.setProperty的目标元素必须是声明该变量的作用域根元素,否则无效 - 批量更新多个变量时,避免频繁触发重排,可先收集变更再一次性
el.style.cssText += ...
真正复杂的地方在于:你得时刻分清当前处理的是编译期静态值(SCSS变量),还是运行时动态实体(CSS变量)。混用两者最典型的后果,就是改了SCSS以为样式会变,结果刷新页面毫无反应——因为那行SCSS早已被编译成固定颜色值,根本没留下任何可覆盖的钩子。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











