Sass变量用于编译期静态值(如断点、z-index),CSS变量用于运行时动态值(如主题色、响应式属性);二者不可混用计算,需通过插值注入Sass值作fallback,并用@each批量生成主题变量,确保key名完全一致。

不能直接在 Sass 中用 $variable 赋值给 --custom-property,也不能在 CSS 里用 var(--x) 反向参与 Sass 编译计算——两者根本不在同一阶段工作。真正可行的协作方式只有一种:Sass 管配置和生成,CSS 变量管运行时取值。
什么时候该用 $primary-color,什么时候该用 --primary-color
编译期确定、不随用户交互或系统偏好变化的值,交给 Sass 变量:$breakpoint-md、$z-index-modal、$font-size-base 这类;运行时可能被 JS 修改、需响应 prefers-color-scheme 或主题切换的值,必须用 CSS 变量:--text-color、--bg-color、--border-radius(哪怕它看起来“固定”)。
常见错误是把所有颜色都写成 CSS 变量,结果在 @media 里写 calc(var(--gap) * 2) 报错——因为 CSS 变量不能参与 Sass 的数学运算;反过来,若把断点写成 --breakpoint-md: 768px,@media (min-width: var(--breakpoint-md)) 在绝大多数浏览器里根本不合法。
-
$breakpoint-md: 768px→ 用于@media (min-width: $breakpoint-md) -
--gap: 1rem→ 用于padding: var(--gap),但不能用于width: calc(var(--gap) * 2)(除非你用container查询或现代env()) - 深色模式下背景色要变?用
--bg-color,由 JS 或:root[data-theme="dark"]控制;但深色模式下的「高亮边框宽度」如果恒为2px,就该用$border-width-highlight
如何让 var(--x) 安全 fallback 到 Sass 值
CSS 变量的 fallback 语法 var(--x, #fff) 里的 #fff 是硬编码字符串,无法复用 $gray-900 这类设计系统变量。正确做法是用插值 #{} 把 Sass 值注入到 CSS 字符串中:
立即学习“前端免费学习笔记(深入)”;
.button {
background-color: var(--bg-primary, #{variables.$color-primary});
border-color: var(--border-default, #{variables.$color-border});
}这样编译后就是 background-color: var(--bg-primary, #0066cc);,既保留了运行时可覆盖能力,又绑定了设计系统的源头值。
PigX UI Pro 前端开发指南 - Vue 3 + TypeScript + Element Plus。当用户提到 PigX UI、PigX 前端、lgb-mgui 项目、Vue 3 企业级后台开发、Element Plus 后台开发时使用此技能。
- 别写
var(--x, $sass-var)—— Sass 会报错 “Invalid CSS” - 如果
$sass-var是函数调用结果(如lighten($base, 10%)),必须包裹在#{}里求值,否则输出的是字面字符串"lighten($base, 10%)" - fallback 值仅在 CSS 变量未定义或无效时生效,不是“默认值”。它不参与主题切换逻辑,只是兜底
如何批量生成主题对应的 CSS 变量
靠手写 :root[data-theme="dark"] { --bg: #1a1a1a; } 不现实。要用 @each 遍历主题 map,并确保 key 名与 JS 设置的 data-theme 和组件中 var(--x) 的键名完全一致:
@use 'themes' as t;
<p>:root {
@each $key, $val in t.$light-theme {
--#{$key}: #{$val};
}
}</p><p>:root[data-theme="dark"] {
@each $key, $val in t.$dark-theme {
--#{$key}: #{$val};
}
}关键约束:map 的 key 必须是字符串(如 "primary-color"),不能是符号(primary-color 会被解析为减法);且所有组件样式里写的 var(--primary-color),其 --primary-color 必须和 map 里的 key 一字不差(包括连字符/下划线、大小写)。
- map 键名用双引号包裹:
"primary-color": #007bff,避免解析歧义 - 不要在
@each里生成带索引的变量名(如--color-#{$i}),这会让调试和 JS 控制变得不可维护 - JS 只负责设置
document.documentElement.dataset.theme = "dark",不手动 setProperty 每个变量——Sass 已预置好整套
为什么不能在 Sass 里直接写 --x: #{$y}
看似省事,实则切断主题切换路径。例如:
// ❌ 危险写法
:root {
--primary-color: #{$primary};
}问题在于:一旦你后续想让 --primary-color 在深色模式下 fallback 到 color-mix(in srgb, white, var(--primary-base) 30%),或者用 JS 动态调整亮度(--primary-lightness: 70),这个硬编码的 --primary-color 就完全无法响应。
- Sass 编译后,
--primary-color已固定为具体颜色值,JS 无法再覆盖它来实现主题过渡动画 - prefers-color-scheme 媒体查询需要同时作用于多个变量,硬编码会让 CSS 文件体积膨胀且逻辑割裂
- 真正灵活的主题系统,CSS 变量必须是“占位符”,它的值由选择器权重(
:root[data-theme])或 JS 动态控制,而非编译时落定
最常被忽略的细节:所有 var(--x) 的 x,必须和 Sass 主题 map 的 key 完全一致——拼写差一个字母,整个主题就断链。这不是语法问题,是协作契约。

















