HTML 压缩值得做,但必须排对优先级:先开服务端 Brotli/gzip,再谈 HTML 最小化。结论是——在已经开启 Brotli 的站点上,HTML 最小化通常只能再省 1%–5% 的传输体积;而没有开启服务端压缩时,它能省下 10%–25%。顺序搞反,投入产出比会差 5 倍以上。
HTML 压缩到底能减小多少体积?
结论:HTML 去空白、去注释、去引号的收益,取决于源文件里「无效字符」的占比,典型静态页面在 10%–25% 之间。
拆开算一笔账:一个 200 KB 的 HTML(含内联 CSS/JS 和大量缩进),执行 collapseWhitespace(合并空白)+ removeComments(删注释)+ removeAttributeQuotes(去属性引号)后,一般能降到 160–170 KB,也就是减掉 15%–20%。但如果内联脚本和样式占比很高,这 15% 里其实大部分是 minifyJS / minifyCSS 的功劳,纯 HTML 标签的空白只占其中一小部分。
关键点在于第二步:这 165 KB 经过 Brotli(质量 6)压缩后大约只剩 20 KB,而压缩前的 200 KB 压完是 21 KB。也就是说,压缩工具在「已经开启 Brotli」的场景下,真正省下的是 1 KB 左右。因为 gzip/Brotli 的字典机制本来就擅长消灭重复的缩进和空格。
HTML 压缩怎么做?各构建工具的具体配置
结论:不要在源码里手写压缩代码,用构建工具在打包阶段自动处理,源码保持格式化。
命令行和库层面,html-minifier-terser 是目前维护最活跃的选择(html-minifier 已停止维护):
npx html-minifier-terser \
--collapse-whitespace --remove-comments --remove-attribute-quotes \
--remove-redundant-attributes --use-short-doctype \
--minify-css true --minify-js true \
index.html -o dist/index.html
构建工具集成:
- Webpack:
html-webpack-plugin 的 minify 字段直接透传上述选项,生产环境传对象、开发环境传 false。
- Vite:默认只压缩 JS/CSS,HTML 空白需装
vite-plugin-html-minifier-terser 并在 plugins 中配置 minifyOptions。
- Next.js:
next.config.js 里的 compress: true 只控制 Node 服务器的 gzip,HTML 空白压缩需自行接 CDN 或中间件处理。
压缩 HTML 会不会改变页面布局?
结论:会,最典型的坑是 inline-block 元素之间的换行空白被吃掉后,间距凭空消失约 4px。
HTML 里两个 display: inline-block 的元素之间若有换行或空格,浏览器会渲染成一个空格宽度的间隙(默认字号 16px 时约 4px)。压缩器把换行删掉后,这个间隙就没了,原本并排卡片之间的缝会收紧。排查方法:检查是否存在依赖「源码换行」产生间距的写法,正确做法是用 font-size: 0 或 gap 属性来控制间距,而不是靠空白字符。
另外两个必须保留的区域:<pre> 和 <textarea> 内部的空白具有语义,主流压缩器会跳过,但自定义正则替换会误伤。removeOptionalTags(删 <html>、<body> 等可选闭合标签)虽然符合 HTML5 规范,但如果你的代码里有字符串匹配 DOM 的实现,建议关掉。
代码格式化与压缩怎么取舍?
结论:源码永远格式化,产物永远压缩,两者靠构建流程分离,不存在「二选一」。
开发阶段用 Prettier 统一格式(默认 printWidth: 80、tabWidth: 2),保证 diff 可读、Code Review 有效、Git 合并冲突可控。构建阶段由 CI 执行压缩,产物不进仓库。唯一例外是需要人工排查线上问题时——Chrome DevTools 的 Sources 面板对 HTML 没有「Pretty print」按钮(JS/CSS 有),所以建议在发布流程里保留一份未压缩的 HTML 到内部环境,方便对照。
服务端压缩和 HTML 压缩,应该先做哪个?
结论:先做服务端压缩,它一次配置对所有静态资源生效,收益远大于 HTML 最小化。
Nginx 开启 gzip:
gzip on;
gzip_comp_level 6;
gzip_min_length 1024;
gzip_vary on;
gzip_types text/html text/css application/javascript application/json image/svg+xml;
Brotli 比 gzip 对文本的压缩率高 15%–25%,需要 ngx_brotli 模块:
brotli on;
brotli_comp_level 6;
brotli_types text/html text/css application/javascript application/json image/svg+xml;
动态压缩用 brotli_comp_level 5 或 6 是延迟与体积的平衡点;如果构建时预生成 .br 静态文件,可以用 11 换最大压缩率。只有当服务端压缩已经就位、且 HTML 是首屏关键路径上的阻塞资源时,HTML 最小化那 1%–5% 才值得投入。
总结一下优先级:服务端 Brotli/gzip > 内联 CSS/JS 的 minify > HTML 空白与注释压缩。压缩 HTML 前先确认 inline-block 间距、pre/textarea 空白不被误删;格式化留给源码,压缩交给构建,两件事不冲突。