sass --style=compressed仅删空格换行注释,不解决选择器爆炸、重复声明或未用类问题;真正压缩需Sass输出expanded格式后,经PostCSS+cssnano深度优化,并配合PurgeCSS裁剪冗余规则。

sass --style=compressed 压完体积几乎不变,不是压缩没开对,而是它根本不管选择器爆炸、重复声明、未用类——只删空格换行注释。真正膨胀来自源码结构失控 + 构建链路缺裁剪。
为什么 --style=compressed 对体积没用
浏览器解析 CSS 的瓶颈是规则数量、选择器长度、匹配复杂度,不是换行符多少。--style=compressed 输出仍保留:
- 深层嵌套生成的冗长后代选择器(如
.layout .sidebar .nav .item a) -
@for $i from 1 through 100产出的 100 条工具类 -
@extend %button-base在多个上下文里调用,生成.header .btn、.modal .btn等重复前缀规则 - 全量
@import "bootstrap.scss"引入,哪怕只用了一个函数 - base64 编码的 sourceMap 直接追加在 CSS 末尾,体积暴增 100KB+
必须把 sassOptions.outputStyle 设为 'expanded'
这是 PostCSS 插件(如 cssnano)能做语义压缩的前提。如果 Sass 先压成一行,cssnano 就没法合并 margin-top: 10px; margin-right: 5px; → margin: 10px 5px 0 0;,也识别不了可删的重复声明。
- Webpack:
sass-loader的options.sassOptions.outputStyle = 'expanded' - Vite:
vite.config.ts中css.preprocessorOptions.sass.outputStyle = 'expanded' - 务必关掉
sourceMap: false(开发时再开),否则压缩后映射错位
PurgeCSS 必须放在 Sass 编译之后、CSS 压缩之前
PurgeCSS 不是预处理器插件,它只能处理已生成的 .css 文件 + 模板路径集合。它扫描 HTML/JS/Vue 中实际出现的类名,整条删除未用规则——这是 gzip 都救不回来的 60%+ 冗余。
- 输入必须是编译后的 CSS 文件 +
content: ['./src/**/*.{vue,js,html,ts}'],不能对.scss直接运行 - Webpack 顺序必须是:
MiniCssExtractPlugin→PurgeCSS→CssMinimizerPlugin - 动态拼接类名(如
className={`btn-${type}`})要加whitelist,否则被误删 - 开发环境禁用 PurgeCSS——热更新时模板路径变化快,容易删掉正在编辑的样式
禁用 @extend,改用 @mixin + CSS 自定义属性
@extend 是体积膨胀重灾区:它不共享声明,只拼接选择器;跨组件调用直接触发组合爆炸;还会让 PurgeCSS 失效——因为工具看到的是不同选择器,不敢删。
立即学习“前端免费学习笔记(深入)”;
- 把颜色、间距、圆角等抽成
:root { --space-sm: 0.5rem; },组件内用margin: var(--space-sm) - 视觉型
@mixin(如card-base())改写为单一类名 + 自定义属性驱动 - 禁止在
@each循环里@include含选择器的 mixin;改用插值生成原子类(如.m-#{$i}),交由 PurgeCSS 裁剪 - 用
@use替代@import,手动导入子模块(如只@use "bulma/sass/elements/button")
@extend、每一层嵌套、每一次全量引入——它们在编译阶段就决定了最终 CSS 的“基因”,后续所有压缩都只是修枝,没法改根。


















