Sass的--style=compressed仅删空格换行注释,不合并选择器、不剔未用类、不简化数值;真正压缩需Sass输出expanded格式后由PostCSS+cssnano处理,并配合PurgeCSS裁剪冗余规则。

SCSS 编译后 CSS 体积大,根本不是压缩参数没开对,而是源码结构失控 + 构建链路缺关键裁剪环节。 单纯加 --style=compressed 或配 cssnano 默认 preset,几乎不减真实体积——它只删空格换行,不删重复声明、不剔未用类、不合并选择器。
为什么 sass --style=compressed 压完体积几乎不变?
因为它是格式整理器,不是压缩引擎。实测 gzip 后体积通常只降不到 3%。真正让 CSS 膨胀的是:
-
@extend %button-base在多个上下文里调用,生成.header .btn、.modal .btn等重复前缀规则 - 嵌套超过 4 层,比如
.card { .list { .item { &:hover { ... } } } },每层都复制父选择器 - 循环生成工具类:
@for $i from 1 through 100 { .m-#{$i} { margin: #{$i}px; } }直接产出 100 条规则 -
@import "bootstrap.scss"全量引入,哪怕只用了一个px2rem()函数
Webpack/Vite 中 Sass 必须走 PostCSS 才能触发真正压缩
很多项目以为装了 postcss.config.js 就自动生效,其实 Sass 文件默认绕过 PostCSS 链路:
- Vite:必须在
vite.config.ts中显式启用css.postcss,并确保preprocess阶段也走postcss-scss解析器 - Webpack:
sass-loader输出后,必须接css-loader→postcss-loader,顺序不能错 -
sassOptions.outputStyle必须设为'expanded'(不是compressed),否则cssnano拿到的是已压缩文本,无法做mergeLonghand等语义压缩
PurgeCSS 必须放在 Sass 编译之后、CSS 压缩之前
PurgeCSS 不是预处理器插件,它只能处理已生成的 CSS 和模板文件。漏掉这步,60%+ 的 CSS 规则可能从未被页面使用过(DevTools Coverage 面板可验证):
立即学习“前端免费学习笔记(深入)”;
- 输入必须是编译后的
.css+ 模板路径集合,例如content: ['./src/**/*.{vue,js,html,ts}'];对.scss文件直接运行无效 - Webpack 中顺序必须是:
MiniCssExtractPlugin→PurgeCSS→CssMinimizerPlugin;放错位置会处理错对象 - 开发环境别启用 PurgeCSS——热更新时模板路径变化快,容易误删正在编辑的样式
- 动态拼接类名(如
className={`btn-${type}`})需手动加whitelist,否则会被删
禁用 @extend,改用 @mixin + CSS 自定义属性
@extend 是体积膨胀重灾区:它不共享声明,只拼接选择器,且会让 PurgeCSS 失效。BEM 场景下尤其危险:
- 不要写
.card__title {@extend %text-emphasis;}—— 它会让同一段样式在每个调用点复制一遍 - 改用
@mixin text-emphasis,各组件显式@include,最终 CSS 仍是独立类名,但声明内容一致,利于 gzip - 把颜色、间距、圆角等抽成
:root { --space-sm: 0.5rem; },组件内用margin: var(--space-sm),最终只有一处声明 - 所有
@mixin内禁止含&:hover、@media或嵌套上下文,否则每次调用都展开整块逻辑
最常被忽略的一点:PurgeCSS 和 @use 都依赖你写的代码“可静态分析”。一旦用了 @extend、动态类名或跨文件无约束的 @import,工具就失去判断依据——体积问题会从构建阶段蔓延到运行时加载和维护成本上。


















