SCSS 本身不会破坏 var() 语法,真正导致 CSS 自定义属性失效的原因通常出在后续的压缩工具错误解析;因此必须选择明确支持 CSS 变量的压缩方案(例如在 cssnano 中禁用 mergeLonghand 和 discardUnused),同时避免继续使用已知不兼容的旧版 minifier。

先直接说结论:真正把 var() 处理坏的,并不是 SCSS 编译器,而是后面的 CSS 压缩环节。像 clean-css、旧版 cssnano,以及 Lara vel 项目中常见的 PHP minifier,往往会在压缩时错误解析,甚至直接删除 var(--x) 这类 CSS 自定义属性语法。问题的核心并不是“把压缩完全关闭”,而是要选对支持 CSS 变量的压缩工具,并关闭容易出问题的压缩规则,这才是避免 SCSS 压缩后 CSS 变量被破坏的正确做法。
为什么 var() 值会被删或变形?
常见问题包括:color: var(--primary); 被压缩后变成 color: ;,或者 margin: var(--space-md) 0; 被错误简化为 margin: 0;,严重时甚至整个 CSS 声明块都会直接消失。
根本原因并不在于 SCSS 编译本身,而是某些 CSS 压缩器把 var() 当成无效函数或无法识别的语法,尤其是在以下情况下更容易出错:
- 启用
mergeLonghand(例如 cssnano 默认开启)后,把margin-top: var(--space-sm); margin-right: 0;错误合并为margin: var(--space-sm) 0 0 0;,随后因为解析失败而被清空 - 启用
discardUnused时,错误地把:root中定义的--xxx判断为“未使用代码”,从而删除整段 CSS 自定义属性定义 - 继续使用已经过时的
clean-css@3.x或matthiasmullie/minify@1.x,这类工具本身就不完整支持 CSS Custom Properties
用 cssnano 时必须关掉这两个选项
如果你的构建流程是 Sass → PostCSS → cssnano(这是目前更推荐的方案),那么 cssnano 依然是相对稳妥的 CSS 压缩工具,但它的默认配置在某些场景下仍可能破坏 var()。
必须显式禁用以下两个选项:
mergeLonghand: false—— 避免把包含var()的单独属性强制合并为简写属性,从而引发解析错误discardUnused: false—— 确保像:root { --color: red; }这样的 CSS 变量定义不会被误删为无用代码
示例配置(postcss.config.js):
module.exports = {
plugins: [
require('cssnano')({
preset: ['default', {
mergeLonghand: false,
discardUnused: false,
}],
}),
],
};Lara vel 项目里慎用 matthiasmullie/minify
虽然文档里写着“支持 CSS 变量”,但从实际测试结果来看,matthiasmullie/minify@1.3.7(当前最新版本)依然可能把 var(--x) 直接解析为空值。尤其是在遇到嵌套写法,或者与 calc() 混合使用时,这类兼容性问题会更加明显,例如:width: calc(100% - var(--gap));。
更可靠的替代方案包括:
- 在前端构建阶段使用
postcss+cssnano完成 CSS 压缩,Lara vel 仅负责加载已经生成好的.min.css文件 - 如果必须在后端执行压缩,可改用
spatie/css-minifier(基于现代 CSS parser,并明确声明兼容var()和@layer) - 彻底避开 PHP 层压缩,让 Nginx 或 Cloudflare 在传输层处理 Gzip/Brotli 压缩,这样通常更安全稳定
SCSS 层也要防一手:别在 @include 里动态拼 var()
这虽然不属于压缩器本身的问题,但确实会进一步放大兼容风险。例如:
@mixin set-color($prop, $var) {
#{$prop}: var(#{$var});
}
@include set-color(color, '--text-primary');这种写法会让压缩工具更难静态分析 var() 是否有效,一些兼容性较差的工具甚至会直接跳过整条声明。
更稳妥的写法,是直接明确写出属性名和变量名:
.btn {
color: var(--text-primary);
}或者在使用 @use 引入变量文件后,通过 meta.load-css 控制注入时机,尽量避免运行时插值影响 CSS 压缩流程。
还有一个很容易被忽略的细节:即便你已经使用了 cssnano,并关闭了 mergeLonghand,如果 SCSS 编译输出阶段仍启用了 outputStyle: 'compressed',某些旧版本 sass(例如 Dart Sass < 2.0.0)依旧可能对 var(--x) 周边空格进行处理。虽然 var(--x) 本身通常没问题,但像 var( --x ) 被压缩成 var(--x) 后,在特定旧工具链中仍可能诱发解析异常。因此更建议开发阶段使用 expanded 输出样式,把最终压缩统一交给 PostCSS 处理,避免两道压缩叠加导致 CSS 自定义属性出错。
