preset: 'default'已足够,因它启用mergeLonghand、normalizeWhitespace等十余项安全优化,实测减体积40%–60%;所谓“不够压”多因@import未处理、重复压缩或忽略源头拆分。

cssnano 本身不支持“深度压缩”——所谓“深度”往往是误配激进选项导致样式崩溃,真正该做的是安全、可控、可验证的压缩。
为什么 preset: 'default' 已经足够,但很多人还觉得“不够压”
默认预设已启用 mergeLonghand、normalizeWhitespace、discardComments、discardDuplicates 等十余项安全优化,实测体积减少 40%–60%。所谓“压得不够”,通常源于:
- 没处理
@import:若cssnano插在postcss-import前,@import "base.css"被当作文本跳过,最终 CSS 缺失内容,体积反而“虚小” - 重复压缩:Webpack 用户开了
css-loader的minimize: true,又加cssnano,导致注释删两遍、空格压两次,但体积收益几乎为零 - 忽略源头:500KB 的单文件
main.css再怎么压,也不如拆成base.css+components.css+pages/home.css后按需加载来得有效
哪些 cssnano 选项绝对不要开
这些配置看似“更省体积”,实际破坏性极强,上线后极易引发样式丢失或 JS 选择器失效:
-
reduceIdents: true:把.btn-primary缩成.a,JS 中document.querySelector('.btn-primary')直接返回null -
discardUnused: true:未配合 PurgeCSS 或 AST 分析(如 HTML/JS 中 class 引用提取),会误删仍在使用的规则 -
zindex: true:自动重排z-index值,破坏原有层叠逻辑,弹窗遮罩可能被按钮盖住 -
convertValues: { length: true }:把16px换成1rem,但项目若未设根字体大小,布局直接错乱
生产构建中必须检查的三个关键点
压缩生效 ≠ 压缩正确。漏掉任意一项,用户就可能缓存旧 CSS 或加载空白样式:
立即学习“前端免费学习笔记(深入)”;
-
contenthash必须绑定到 CSS 文件名:例如main.[contenthash:8].css,否则修改样式后,浏览器仍用缓存中的旧文件 -
html-webpack-plugin必须动态注入<link>标签:硬编码<link href="main.css">会绕过 hash,永远加载未更新的文件 - 所有 CSS 入口都要走同一压缩链:比如
src/index.css和src/theme/dark.css都要被css-minimizer-webpack-plugin处理,不能只压主文件、漏掉主题文件
替代“深度压缩”的更有效手段
与其在 cssnano 配置里反复试错,不如转向更稳定、可度量的优化路径:
- 用
purgecss(或unocss/windi-css)做类名级摇树:删掉未在 HTML/JS 中出现的.u-mt-4、.is-active等规则,比压缩空格收益高一个数量级 - 对 SVG 图标改用
postcss-inline-svg:把url("icon.svg")内联为url("data:image/svg+xml,..."),避免额外 HTTP 请求 - 拆分并设置
media属性:<link href="print.css" media="print">不阻塞首屏渲染,prefetch关键组件 CSS 可进一步降低 FCP
真正容易被忽略的不是“能不能压得更狠”,而是压缩是否覆盖全部入口、hash 是否生效、HTML 中的链接是否由构建工具动态生成——这三处出问题,再小的 CSS 文件也白压。


















