--style=compressed不能解决冗余问题,它仅删除空格换行,不减少选择器数量、重复声明或未用类;真正膨胀源于@extend爆炸、深层嵌套、@import全量引入和工具类泛滥,需从源码结构与构建链路双管齐下治理。

开 --style=compressed 不解决冗余问题,它只删空格换行;真正膨胀来自 @extend 爆炸、深层嵌套、全量 @import 和未用工具类,必须从源码结构和构建链路双头治理。
为什么 compressed 模式对冗余无效
浏览器解析 CSS 的瓶颈不是格式,而是选择器数量、匹配深度和声明重复。而 compressed 输出仍保留:
• 所有嵌套生成的后代选择器(如 .layout .sidebar .nav a)
• 100 个 .m-1 到 .m-100 工具类
• @extend 复制出的 47 份相同 margin 声明
• sourceMap 开启时追加的 base64 字符串(体积 +100KB+)
实测 gzip 后体积差异常小于 3%,说明内容冗余才是主因。
停用 @extend,改用 %placeholder + 自定义属性
@extend 是体积爆炸重灾区:它不共享声明,只拼接选择器;跨上下文调用直接触发组合爆炸(如 .card .btn, .modal .btn)。安全替代路径是:
• 仅对无状态、无上下文、可直接加到 HTML 的原子行为使用 %,例如 %sr-only、%clearfix
• 禁用含 :hover、@media、&__header 的占位符——它们必然导致冗余输出
• 把颜色、间距、圆角等抽成 CSS 自定义属性::root { --space-sm: 0.5rem; },组件内统一用 margin: var(--space-sm)
用 @use 替代 @import,并配 sideEffects
@import 是文本拼接,哪怕只调用一个 px2rem(12),也会把整个 _utils.scss 全塞进输出;@use 则按需加载,且自动加命名空间隔离:
• 必须用 Dart Sass ≥1.23.0(node-sass 已废弃)
• @use "colors" as color 后,必须写 color.$primary,不能直接写 $primary
• 在 package.json 中声明:"sideEffects": ["*.scss", "src/styles/**/*.scss"],告诉 Webpack 这些文件无副作用,允许裁剪
• 跳过框架入口文件,手动 @use 子模块:@use "bootstrap/scss/functions"、@use "bootstrap/scss/grid"
立即学习“前端免费学习笔记(深入)”;
编译后必须加 PurgeCSS,且配置不能漏路径
PurgeCSS 必须在 Sass 编译之后、CSS 压缩之前介入,才能基于真实模板扫描并删除未用规则:
• 输入必须是已生成的 .css + 模板集合,不能对 .scss 直接运行
• content 字段必须覆盖所有模板路径,例如 ["src/**/*.{vue,html,js}"],漏一个就可能保留整套未用组件样式
• Webpack 中顺序必须是:MiniCssExtractPlugin → PurgeCSS → CssMinimizerPlugin
• 开发环境禁用 PurgeCSS:热更新时模板路径变化快,容易误删正在编辑的样式
最易被忽略的是嵌套层级控制——每深一层,Sass 就复制一次父选择器前缀;.card { .header { h1 { } } } 看似简洁,但若被 5 个组件复用,就会产出 5 组完全相同的 .card .header h1 规则。限制在 3 层以内,比任何压缩开关都管用。


















