Base64 为什么会增加 33% 体积

2026-09-30 · 1191 词

Base64 会把数据变大。不是稍微大一点 —— 是每次大三分之一,没有例外,也没有可调的开关。这个数字不是某个实现的怪癖,它直接从编码规则里推出来;搞清楚它是怎么来的,内联与否的决策就会容易得多。

那三分之一从哪来

Base64 的存在,是为了只用"能在文本传输中存活"的字符来表示任意字节。它的字母表有 64 个符号,也就是每个字符 6 位信息;而字节是 8 位。所以编码器一次读 3 个字节(24 位),写出 4 个字符(4 × 6 = 24 位)。

三个字节进,四个字符出:

3 字节 → 4 字符        4 / 3 = 1.333...

故事就这么多。300,000 字节的图片变成 400,000 个字符的字符串。开销精确地是 33.3%,而且只作用于载荷本身 —— data:image/png;base64, 这个前缀另加 22 个字符,对小资源有意义,对大资源无关紧要。

唯一能调节的是填充。如果输入长度不是 3 的倍数,最后一组会用不携带信息的 = 补齐,所以精确长度是 4 × ceil(n / 3):

小输入那几行,正是"为了省体积而内联小资源"站不住脚的理由:1 字节的文件变成 4 个字符加 22 个字符的前缀,前缀才是主角。

为什么 gzip 救不了你

对文本,gzip 通常能压掉 60–80%,所以"33% 无所谓"这句话有时会被拿出来说。这个推理对 JSON 和 HTML 成立,对图片完全失效。

压缩靠的是找冗余。JPEG、PNG、WebP、AVIF 已经把冗余基本去干净了 —— 那正是这些格式的工作 —— 所以它们的字节在压缩器看来接近随机。Base64 把这些不可压缩的字节编码进一个只有 64 个符号的受限字母表,并没有引入任何压缩器可利用的冗余。结果是两头都输:数据大了 33%,而且依然压不动。

一条命令就能量出来:

# 一张真实图片,本身已经压缩过
base64 -w0 photo.jpg > photo.b64
ls -l photo.jpg photo.b64
gzip -9 -c photo.b64 | wc -c    # 比 photo.b64 大不了多少,也小不了多少

文本载荷的情况不一样。如果你 Base64 编码的是一段文本(JSON、XML、日志),gzip 对编码后的形态能压得很好,有时甚至比压原文更好,因为文本的 Base64 里仍然有可识别的结构。所以"gzip 能不能消掉那 33%"有两个答案,完全取决于载荷原本是否可压缩。

成本不只是字节

把样式表或 HTML 文档撑大,有三项成本不会出现在文件大小对比里:

  1. 阻塞渲染。 放在 <style> 块或外链 CSS 里的 data URI 是那个文件的一部分。浏览器必须先下载再解析,解析完才能绘制。而一张外链图片的请求不在这条关键路径上。
  2. 无法独立缓存。 内联了二十个图标的样式表,改一个字节,每个访客就要重新下载全部二十个。作为独立文件时,它们各有各的缓存条目和校验器。
  3. 解析与内存。 这些字节必须先被解码、以字符串形式持有,才能变成图片。样式表里一段 400 KB 的字符串,就是解析器必须走完的 400 KB 文本,而且它会一直留在 CSSOM 里。

这些都不致命。但只要你只比较文件大小,它们全都是隐形的。

盈亏平衡点到底在哪

不存在通用阈值,但决策区间足够窄,可以写成几条经验规则:

对图片来说,比"这段 Base64 有多大"更好的问题是:它能不能是 SVG? 一个矢量 Logo 只有几百字节的路径数据,编码后不到 1 KB,而且与分辨率无关。内联它显然是赚的,也是这项技术赢得好名声的场景。

在你自己站点上量一量

两个数字就能说明内联是否有收益:包含 data URI 的文档的传输大小,以及用外链资源的等价页面的传输大小。如果内联版本大 30%,那就是大 30% —— 那 33% 不可能被网络层拿回来。

这个测量有一种典型的做错方式:拿图片的未压缩大小去比文档的压缩后大小。要同口径比较,并且记住 data URI 的字节是在一个 gzip 只能部分压缩的响应里传输的。我们的 PNG 转 Base64 和 JPG 转 Base64 页面会在转换时报告输出长度与开销,通常足够让你立刻看出:一张 900 KB 的照片不该被内联成背景图。

对于你确实需要那个字符串的场景 —— 关键 CSS 里的小图标、无法引用外部文件的邮件模板、单文件 HTML 导出、测试里的 JSON 夹具 —— 这份开销是"自包含"的合理代价,而知道确切数字,能让它成为一个有意的选择而不是意外。如果你比较的是"在内存里持有图片"的两种方式而不是写进文档,data URI 与 blob URL 讲的是这个权衡的另一半。

相关阅读

试用 Base64 转图片工具 →