HTML 压缩到底压掉了什么:去空白、去注释、折叠标记的完整指南
讲清楚 HTML 压缩去掉的是哪些字节,空白和注释怎么折叠,压缩为什么能和 gzip 叠加再省一层,以及为什么 pre 和 textarea 里的空白必须原样保留。
HTML 压缩到底压掉了什么:去空白、去注释、折叠标记的完整指南
很多人以为 HTML 压缩就是把代码挤成一行,看着难受,省的字节也不多。真去量一遍才发现,一份手写或模板引擎吐出来的 HTML,压缩后通常能小 40% 到 60%。这些字节不是凭空消失,是有明确来源的:标签之间的换行和缩进、调试用的注释、冗余的属性引号、能被 parser 推断出来的可选闭合标签。这篇把每一类都拆开讲,顺便说清楚一个常被忽略的点:HTML 压缩和服务器的 gzip 不是二选一,它们是叠加的。
压缩动的是哪几类字节
第一类是标签之间的空白。模板引擎为了源码可读,会在每个标签前面塞缩进,在每行结尾留换行。这些空白对渲染没有任何意义,parser 会直接当成可忽略的空白节点丢掉。把 tag 之间的空白全部折叠,这一项往往就贡献了一半的体积。
第二类是文本节点内部的连续空白。<p> 这是 一段话 </p> 里那些多余的空格,折叠成单个空格不会改变浏览器里看到的样子,因为 HTML 本来就把连续空白渲染成一个。
第三类是注释。开发阶段写的 <!-- 这里是导航区 --> 全部可以删,但要留个心眼:<!--[if mso]> 这种 Outlook 条件注释、<!--#include virtual="..."--> 这种 SSI 指令长得像注释,删了页面就坏了。靠谱的压缩工具默认会保留它们。
第四类是属性和闭合标签的冗余。id="x" 在值不含空格、引号、等号、尖括号时可以写成 id=x,这是 HTML5 规范允许的;disabled="disabled" 可以缩成 disabled;</li>、</p> 这类在下一个兄弟节点能推断出闭合时,可以直接省掉。
看一个真实例子
下面是压缩前的一小段:
<ul class="nav">
<!-- 主导航 -->
<li class="item">
<a href="/home">首页</a>
</li>
<li class="item">
<a href="/about">关于</a>
</li>
</ul>
压缩后:
<ul class=nav><li class=item><a href=/home>首页</a><li class=item><a href=/about>关于</a></ul>
原文 156 字节,压缩后 91 字节,省了 42%。注释没了,标签间空白没了,class="nav" 的引号去了,</li> 也省了。浏览器解析这两段得到的 DOM 完全一致。
首屏体积为什么值得抠这几 KB
HTML 文档本身是首屏的关键路径资源,浏览器必须先把它下载、解析完,才能去发现里面引用的 CSS 和 JS。文档越小,这一步越快,后面的资源也越早开始排队。在弱网或者高延迟的移动端,文档大小直接影响首字节到可交互的间隔。
有几个硬性体积线更现实:Gmail 对邮件正文有 102 KB 的裁剪阈值,超过就会被折叠到「邮件已截断」链接后面;AMP 规范拒收文档 HTML 超过 75 KB 的页面。这些场景里压缩不是锦上添花,是过线与否的区别。
我自己经手过一个针对 Outlook 的事务邮件模板,嵌套表格加重复内联样式,原始 90 KB。开着「保留条件注释」压一遍,正文降到 38 KB,稳稳跨过 Gmail 那条 102 KB 线,退订页脚终于能完整显示出来。那次之后我把压缩这一步直接写进了发件前的流程。
和 gzip 是叠加,不是替代
经常有人说,反正服务器开了 gzip,源码里的空白会被压掉,何必再 minify。这话只对了一半。gzip 擅长压缩重复的字节序列,你的缩进确实会被它压得很好。但 minify 和 gzip 处理的不是同一层东西。
minify 是结构层面的删除:注释、可选标签、冗余引号,这些字节被真正去掉了,gzip 之前的输入就更小。gzip 是熵编码,它压的是删除之后剩下的内容。两者叠加,通常比单独 gzip 再小 5% 到 15%。换句话说,先 minify 再 gzip,传输体积比只 gzip 更小,而且解压后浏览器要解析的字节也更少,解析本身也省了。
CSS 和 JS 也是同理。HTML 压缩只动标记,<style> 和 <script> 里的内容它一个字节都不碰。要把内联样式和脚本也压掉,得分别走 CSS Minifier 这类专门工具,三样一起压才是发布前完整的一遍。
一条不能踩的红线:pre 和 textarea
压缩里最容易出事的地方,是 raw text 元素。<pre> 按字面渲染空白,你写了几个空格几个换行,页面上就是几个;<textarea> 的初始值字符精确,多一个空格都会出现在输入框里;<script> 和 <style> 内部是代码,字符串字面量里的空白有语义。
这四类元素的内容,任何正经的 HTML 压缩工具都会按 HTML5 规范当成 raw text,字节级原样保留,绝不折叠。出问题的常见情形是:你粘了一段开在 <pre> 里、却没带上 <pre> 父标签的片段,tokenizer 看不出这是 raw text,就把你要留的空白折叠了。所以粘片段时永远把外层元素一起带上。
HTML 压缩工具 把上面每一项变换都做成了独立可关的 checkbox,raw text 保护是默认且不可绕过的,输出下方实时显示压缩前后体积和节省百分比。粘进去,看着数字往下掉,该关的开关自己关,这件事就这么简单。
Made by Toolora · Updated 2026-06-13