开发者工具 · Base64 编码器和解码器
CSS 中的内联 Base64 图像:何时 data: URI 有帮助,何时有害
· 为什么它很重要
base64 性能
将图像内联为 Base64 数据:URI 会删除请求,但会增大文件并破坏缓存。这篇文章列出了何时值得进行交易以及何时使用单独的文件更快。
增长到数百 KB 的样式表 — 一个团队的内联习惯及其在加载时间中的表现
开发团队决定将小图标内联为 Base64 数据:CSS 中的 URI 将减少 HTTP 请求并提高页面加载速度。随着时间的推移,随着更多图标的添加,样式表增长到 400 千字节。
CSS 包本来应该包含样式规则,但现在以图像数据为主。团队测量了加载时间,发现页面比内联之前更慢,而不是更快。问题变得清晰起来:400-kilobyte 样式表在每个页面加载时下载并缓存每个页面,而如果图标是单独的文件,则单个图标文件将被缓存并在每个页面之间共享。
什么数据:URI 内联以及为什么它是 Base64 — 语法、媒体类型和大小损失
向网站添加更多页面会使问题变得更糟,因为每个页面都会再次下载包含所有内嵌图像的相同样式表。这篇文章解释了什么是 data: URI、为什么它是 Base64、内联如何影响缓存和性能,以及决定何时值得进行权衡的经验法则。 data: URL 是一种将资源直接嵌入 HTML 或 CSS 文件而不是链接到外部文件的方法。语法为 data:mediaType;base64,encoded_bytes。
mediaType 声明后面的资源类型,例如用于 SVG 的 image/svg+xml、用于 PNG 的 image/png 或用于文本的 text/plain。 ;base64 标志表示有效负载是 Base64 编码的而不是百分比编码的文本。 encoded_bytes 是实际数据。当浏览器在 href、src 或 background-image 属性中遇到 data: URL 时,它会解码 Base64 并内联呈现资源。不会发生 HTTP 请求,因为资源已经存在并嵌入到父文档中。这可以节省一个或几个 HTTP 请求,这在每个请求都有开销的 HTTP/1.1 世界中很重要。
缓存和关键路径 - 为什么每个包含样式表的页面都会再次下载内联字节
在 HTTP/2 或 HTTP/3 世界中,许多请求可以通过一个连接进行多路复用,因此节省的空间较小。 Base64 编码的大小损失是直接且显着的。当保存为 XML 文件时,SVG 图标为 3 千字节,当进行 Base64 编码并嵌入为数据:URI 时,该图标将变为 4 千字节。必须将因编码而增加的 33% 大小添加到包含样式表的每个页面。如果在十页上使用该图标,则样式表将下载十次,每次都包含相同的 4 千字节编码图像。
如果图标是一个单独的文件,则 3 KB 的原始文件将被下载一次并缓存,然后在所有十个页面上从缓存中使用。对于大多数图标来说,经济选择是显而易见的:单独的文件总体上更小。仅当图标仅在一页或极少数页面上使用且该图标对该页面确实至关重要时,内联优势才适用。每个页面上都出现的图标不太适合内联;最好作为单独的缓存文件。
客户端解析成本 — CSS 和 HTML 解析器处理多大的内联字符串,定性描述
仅在登陆页面上使用的一次性插图可能会受益于内联以保存请求。缓存抵消了内联数据的大部分好处:样式表中的 URI。样式表通常会缓存数天或数周。下载样式表后,即使浏览器已经缓存了该图像,也会再次下载其中内嵌的每个资源。如果更新样式表,即使只更改了一项 CSS 规则,也必须重新验证或重新下载所有内联数据。
这会导致膨胀:颜色或间距的更改会触发样式表的完全重新下载,包括未更改的千字节图像数据。单独的图像文件可以使用自己的过期标头独立缓存、单独更新并在样式表和页面之间重复使用。当资源是单独的文件时,浏览器缓存的效率比资源嵌入到较大文档中时要高效得多。当大型 Base64 字符串嵌入到样式表中时,解析和渲染成本会增加。 CSS 解析器在应用规则之前必须读取整个样式表。
工作示例:将一个小 SVG 图标内联为文本 — 将标记粘贴到编码器中并手动组装数据:URI
具有内联 Base64 的 400 千字节样式表是 400 千字节的文本,必须在应用任何规则之前对其进行解析。渲染具有大数据的页面的 HTML 解析器:样式属性或背景图像属性中的 URI 必须解码 Base64 并在元素渲染之前构造图像。对于简单的 SVG 图标来说,这是微不足道的。对于更复杂的图像或更大的图标,解码和渲染发生在主线程上,可能会阻塞交互性。定性成本是真实的,但如果不进行分析就很难衡量。
通常,如果内联图像大于几千字节,则单独的文件速度更快。一个有效的例子展示了确切的权衡。采用一个简单的 SVG 箭头图标,1.2 千字节的 XML。 Base64 编码后,它变为 1600 个字符,或大约 1.6 千字节,并带有 data: URL 前缀。带有背景图像的单独 CSS 规则: url(/icons/arrow.svg) 可能会向样式表添加 40 字节。图标文件下载一次、缓存并重复使用。内联会为该图标保存一个 HTTP 请求,但会向每个样式表加载添加 1.6 千字节。
有效的经验法则 — 小型、关键、一次性资产内联;其他一切都作为文件
如果样式表为 50 千字节并在 20 页面之间共享,则内联该图标会使每次站点访问的总下载量增加 32 千字节。它节省的HTTP请求最多就是几百字节的开销。该请求也会在 HTTP/2, 中自动复用,从而消除开销差异。除非样式表很小、图标很大或者图标恰好出现在一页上而不是其他地方,否则内联交易会损失惨重。经得起审查的经验法则是有限且具体的。
可以内联微小的、关键的、一次性的资产。仅出现在一个不寻常页面上的 200 字节 SVG 箭头可能会被内联以节省请求开销。其他一切都应该分开。关键渲染路径逻辑很重要:如果图标必须立即可见并且每一毫秒的加载时间都会消耗转换,那么内联可能会获胜。对于具有典型图标的典型页面,单独的文件几乎总是更好。使用您的实际资产测试这两种方法,并测量页面负载、缓存命中率和请求瀑布。
这不包括什么 - HTTP/2 和 HTTP/3 多路复用细节和图像格式压缩
不要假设内联是一种无需测量的优化。导致样式表臃肿的最简单方法是增量内联,而不测量每次添加是否实际上更快。 Base64 编码器和解码器可帮助您在进行内联之前做出此决定。将 SVG 标记或其他图标源作为文本粘贴到工具中。单击编码并设置选项以生成数据:URI。该工具会向您显示数据的准确长度:URL。将其与单独的 CSS 规则和资源文件本身的大小进行比较。
计算需要多少页共享样式表才能在内联文件与单独文件之间实现收支平衡。组装 data: URI 并在将其提交到样式表之前在实际的 HTML 页面中对其进行测试。如果 URI 长于几百个字符,则嵌入的成本可能大于保存请求的好处。使用该工具测试您的实际图标和资源,然后测量内联前后对实际页面加载指标的影响。
要点:谨慎内联并测量 — Base64 编码器和解码器如何让您对 SVG 标记进行编码并在提交之前查看确切的大小
高性能方法是对内联进行选择性。每个页面或多个页面上使用的图标是单独的缓存文件。仅在一页上使用的图标或对首次绘制真正关键的图标可以内联。权衡您的实际资产和页面,而不是遵循一般建议。在将任何内联资源添加到样式表之前,使用 Base64 编码器和解码器查看其确切大小。尺寸损失是真实存在的,并且在每次页面浏览时都会成倍增加。
缓存和请求多路复用使得内联的原始好处不再那么重要。对于大多数现代应用程序来说,更小的样式表和来自单独文件的更好的缓存效率超过了请求开销。谨慎地内联,衡量结果并信任衡量结果而不是直觉。