SCSS变量($color)与CSS变量(--color)本质不同:前者编译时替换为具体值,天然兼容旧浏览器;后者是运行时特性,需PostCSS降级且仅支持:root下纯常量定义。

SCSS 本身不生成 CSS 变量(--x),它编译后只是普通 CSS;所谓“SCSS 中定义的 CSS 变量不生效”,实际是开发者误把 SCSS 变量($color)当成了 CSS 自定义属性(--color),或在 SCSS 里写了 --color: #007bff 但没意识到:这些声明能否在旧浏览器中工作,完全取决于最终输出的 CSS 是否含 var(--x),以及是否做了降级处理。
SCSS 变量($color)和 CSS 变量(--color)根本不是一回事
SCSS 的 $color: #007bff 在编译时就被替换成具体值,输出里根本不会出现 var() —— 所以它天然兼容 IE8。而你写的 --color: #007bff 是纯 CSS 声明,属于运行时特性,IE11 及更早版本会静默丢弃整条规则。
-
$primary: red;→ 编译后变成color: red;,旧浏览器照常解析 -
:root { --primary: red; }→ 输出就是:root { --primary: red; },IE11 直接跳过整行 - 混用时写
color: var(--primary);→ 输出含var(),旧浏览器失效,不是 SCSS 的问题,是 CSS 特性本身不支持
PostCSS 降级没生效,多半是 preserve: false 漏配或配错
如果你在 SCSS 里写了 :root { --primary: #007bff; },又希望旧浏览器能用上这个值,必须靠 postcss-custom-properties 插件静态替换。但默认配置下它只追加降级值,比如:
background: #007bff;<br>background: var(--primary);
IE11 看到第二行就跳过,最终背景变透明。必须显式设 preserve: false 才会删掉 var() 行,只留第一行。
立即学习“前端免费学习笔记(深入)”;
-
preserve: true→ 保留var()行,供现代浏览器动态用,旧浏览器失效 -
preserve: false→ 彻底删除含var()的声明,只输出静态值,旧浏览器可用,但 JS 动态改变量无效 - 不写
preserve或写成null→ 默认等同false,但容易误判,建议始终显式声明
变量定义位置或值不符合静态替换前提
postcss-custom-properties 是编译期工具,只能处理构建时“一眼能看清”的变量:必须定义在 :root,值为纯常量,不能跨文件、不能含 calc()、不能嵌套引用其他变量。
- ✅ 安全写法:
:root { --primary: #007bff; --gap: 12px; } - ❌ 无法替换:
:root { --size: calc(1rem + 2px); --c: var(--base); } - ❌ 局部定义默认不处理:
.card { --pad: 1rem; },除非配importFrom显式引入该文件 - ❌ 媒体查询内定义的变量(如
@media (min-width: 768px) { :root { --gap: 16px; } })通常无法被回溯解析
构建后仍有 var(-- 残留,说明降级根本没跑通
运行构建后,打开产出的 CSS 文件,全局搜索 var(--。只要还有,就说明:
- 变量定义跨了文件(比如
variables.css里定义,button.css里用),插件看不见 - 值里有
calc()或 JS 动态设置(document.documentElement.style.setProperty('--c', 'red')),插件无法捕获 - PostCSS 插件没启用,或执行顺序错误(必须在
autoprefixer之前) - 同时用了
css-vars-ponyfill却配了preserve: false,导致 ponyfill 找不到原始var()而跳过
最易被忽略的一点:SCSS 编译器对 --x 声明完全无感,它既不报错也不处理——你写的 --color: $primary 会被原样输出,后续是否降级,全看 PostCSS 配置和变量定义是否满足硬性条件。


















