HTML 性能优化
HTML 默认情况下快速
且易于访问
。作为开发者,我们的工作是在创建或编辑 HTML 代码时确保保持这两个特性。例如当嵌入的 video 文件大小过大,或者 JavaScript 解析阻塞了关键页面元素的渲染时,情况可能会比较复杂。本文将引导你了解关键的 HTML 性能特性,以大幅提高网页质量。
HTML 性能关键问题
就性能而言,HTML 非常简单,它主要是文本,文本大小较小,因此下载和渲染速度通常很快。影响网页性能的关键问题包括:
图像和视频文件的大小
需要考虑如何处理替换元素(例如 <img>
和 <video>
)。图像和视频文件较大,可能会显著增加页面的大小。因此,需要尽量减少下载到用户设备的字节数(例如,为移动设备提供较小的图像)。还需要考虑仅在需要时加载页面上的图像和视频,以改善感知性能。
考虑 iframe
通常是嵌入在 <iframe>
元素中的内容。将内容加载到 <iframe>
中可能会显著影响性能,因此应该仔细考虑。
资源加载顺序
为了最大化感知性能和实际性能,HTML 应该首先按照在页面上出现的顺序加载。然后,你可以利用各种特性来影响资源加载顺序以获得更好的性能。例如,你可以提前预加载关键的 CSS 和字体,但将非关键的 JavaScript 推迟到稍后加载。
注意
简化 HTML 结构和对源代码进行压缩可以加快渲染和下载速度是有道理的。然而,与图像和视频相比,HTML 文件大小微不足道,而且现代浏览器的渲染速度非常快。
如果你的 HTML 源代码非常庞大且复杂,导致渲染和下载性能受到影响,那么你可能存在更大的问题,并且应该考虑简化
和拆分
内容。
响应式处理替代元素
// todo 后续有时间可添加响应式设计相关文章
响应式设计 彻底改变了在不同设备上处理网页内容布局的方式。它的一个关键优势是可以动态切换根据不同的屏幕尺寸优化后的布局,例如宽屏布局与窄屏(移动设备)布局之间的切换。它还可以根据其他设备属性,如分辨率或亮色或暗色配色方案的偏好,来处理内容的动态切换。
所谓的“移动优先”技术可以确保默认布局适用于小屏幕设备,因此移动设备只需下载适合其屏幕的图像,无需下载更大的桌面图像,以此提高性能。然而,由于这是通过 CSS 中的媒体查询来控制的,因此它只能对在 CSS 中加载的图像的性能产生积极影响。
通过 srcset 提供不同的图像分辨率
要根据设备的分辨率和视口大小提供相同图像的不同分辨率版本,你可以利用 srcset 和 sizes 这两个属性。
下面是一些代码示例:
以下示例为不同屏幕宽度提供了不同尺寸的图像:
<img
srcset="480w.jpg 480w, 800w.jpg 800w"
sizes="(max-width: 600px) 480px,
800px"
src="800w.jpg"
alt="家庭照"
/>
2
3
4
5
6
7
srcset 提供源图像的固有尺寸以及它们的文件名,而 sizes 在每种情况下提供媒体查询和需要填充的图像槽宽度。然后,浏览器根据每个槽位决定加载哪些图像。例如,如果屏幕宽度小于等于 600px,那么 max-width: 600px 为真,因此需要填充的槽位是 480px。在这种情况下,浏览器很可能选择加载 480w.jpg 文件(480px 宽的图像)。这有助于性能提升,因为浏览器不会加载比所需更大的图像。
以下示例为不同屏幕分辨率提供了不同分辨率的图像:
<img srcset="320w.jpg, 480w.jpg 1.5x, 640w.jpg 2x" src="640w.jpg" alt="家庭照" />
为图像和视频提供不同来源
<picture>
元素基于传统的 <img>
元素,允许你为不同的情况提供多个不同的源。例如,如果布局是宽的,你可能希望有一个宽的图像,如果是窄的,你将希望有一个在该上下文中仍然有效的较窄的图像。
当然,在移动设备上,这也有助于通过提供较小的信息下载来提高性能。
下面是一个示例:
<picture>
<source media="(max-width: 799px)" srcset="narrow-banner-480w.jpg" />
<source media="(min-width: 800px)" srcset="wide-banner-800w.jpg" />
<img src="large-banner-800w.jpg" alt="茂密森林景观" />
</picture>
2
3
4
5
<source>
元素在 media 属性中包含媒体查询。如果媒体查询返回 true,则加载其 <source>
元素的 srcset 属性中引用的图像。在上面的示例中,如果视口宽度为 799px 或更小,则加载 narrow-banner-480w.jpg 图像。还要注意 <picture>
元素包含了一个 <img>
元素,在不支持 <picture>
的浏览器中提供了默认图像加载。
请注意,在此示例中使用了 srcset 属性。如前一节所示,你可以为每个图像源提供不同的分辨率。
<video>
元素在提供不同来源方面的工作方式类似:
<video controls>
<source src="video/smaller.mp4" type="video/mp4" />
<source src="video/smaller.webm" type="video/webm" />
<source src="video/larger.mp4" type="video/mp4" media="(min-width: 800px)" />
<source src="video/larger.webm" type="video/webm" media="(min-width: 800px)" />
<!-- 在不支持 video 元素的浏览器中的备用 -->
<a href="video/larger.mp4">下载视频</a>
</video>
2
3
4
5
6
7
8
9
然而,提供图像和视频的源之间存在一些关键差异:
- 在上面的示例中,我们使用的是 src 而不是 srcset;你无法通过 srcset 指定视频的不同分辨率。
- 相反,要在不同的
<source>
元素中指定了不同的分辨率。 - 请注意,我们还在不同的
<source>
元素中指定了不同的视频格式,每个格式都在 type 属性中通过其 MIME 类型进行标识。浏览器将加载它们支持(媒体查询测试返回 true)的首个格式。
图像的懒加载
提高性能的一个非常有用的技术是懒加载。这指的是在 HTML 渲染时不立即加载所有图像,而是仅在它们实际对用户可见(或即将可见)时加载它们。这意味着立即可见/可用的内容更快地准备就绪,而随后的内容只有在滚动到时才会渲染其图像,并且浏览器不会浪费带宽加载用户永远看不到的图像。
懒加载通常使用 JavaScript 处理,但现在浏览器有一个可用的 loading 属性,可以指示浏览器自动进行图像的懒加载:
<img src="800w.jpg" alt="家庭合照" loading="lazy" />
你还可以使用 preload
属性来对视频内容进行延迟加载。例如:
<video controls preload="none" poster="poster.jpg">
<source src="video.webm" type="video/webm" />
<source src="video.mp4" type="video/mp4" />
</video>
2
3
4
将 preload 的值设置为 none 告诉浏览器在用户决定播放视频之前不要预加载任何视频数据,这对性能显然是有益的。相反,它只会显示由 poster 属性指示的图像。不同的浏览器具有不同的默认视频加载行为,因此最好明确指定。
处理嵌入内容
嵌入内容最常用的方式是使用 <iframe>
元素,尽管还存在其他不太常用的嵌入元素,如 <object>
和 <embed>
。在本节中,我们将重点关注 <iframe>
。
最重要也是最关键的建议是:“除非非常必要,否则不要使用嵌入式 <iframe>
”。如果你要创建一个包含多个不同信息窗格的页面,你可能会觉得把它们分成单独的页面并加载到不同的 <iframe>
中是有组织性的。但是,这样做会带来一些性能和其他方面的问题:
将内容加载到
<iframe>
中比将内容作为同一直接页面的一部分加载要消耗资源得多——不仅需要额外的 HTTP 请求来加载内容,而且浏览器还需要为每个<iframe>
创建一个单独的页面实例。每个<iframe>
实际上是嵌入在顶级网页中的一个独立网页实例。你还需要为每个不同的
<iframe>
分别处理任何 CSS 样式或 JavaScript 操作(除非嵌入的页面来自同一源),这变得更加复杂。你无法使用应用于顶级页面的 CSS 和 JavaScript 来定位嵌入的内容,反之亦然。这是一项合理的安全措施,是 Web 的基本原则。每个
<iframe>
还需要单独加载所有共享的数据和媒体文件——你无法在不同的页面嵌入之间共享缓存的资源(再次强调,除非嵌入的页面来自同一源)。这可能导致页面使用的带宽比你预期的要多得多。懒加载 iframe
与 <img>
元素一样,你还可以使用 loading 属性指示浏览器对最初屏幕外的 <iframe>
内容进行懒加载,从而提高性能:
<iframe src="https://example.com" loading="lazy" width="600" height="400"> </iframe>
处理资源加载顺序
资源加载的顺序对于最大化感知和实际性能非常重要。当加载网页时:
- 通常首先解析 HTML,按照页面上的顺序进行解析。
- 解析任何找到的 CSS,以理解应该应用于页面的样式。在此期间,开始获取链接的资源,如图像和 Web 字体。
- 解析任何找到的 JavaScript,对页面进行评估和执行。默认情况下,这会阻止解析遇到的
<script>
元素之后的 HTML。 - 稍后,浏览器根据应用于它的 CSS 来确定每个 HTML 元素应该如何进行样式化。
- 将经过样式化的结果绘制到屏幕上。
处理 JavaScript 加载
解析和执行 JavaScript 会阻塞后续 DOM 内容的解析。这就增加了页面渲染和用户要使用该内容所需等待的时间。一个小的脚本不会有太大影响,但考虑到现代 Web 应用程序通常非常依赖 JavaScript,这一点很重要。
默认的 JavaScript 解析行为的另一个副作用是,如果正在渲染的脚本依赖于页面后面出现的 DOM 内容,将会出现错误。可以通过在 <script>
元素中添加 async 属性来实现更好的性能
还有另一个属性 defer,它会使脚本在文档解析完成之后、DOMContentLoaded 事件触发之前执行。这与 async 有类似的效果。
处理 JavaScript 加载的另一个技巧是将脚本拆分为代码模块
,并在需要时加载
每个部分,而不是将所有代码放入一个巨大的脚本并在开头加载。这可以通过使用 JavaScript 模块来实现。
使用 rel="preload" 预加载内容
从 HTML、CSS 和 JavaScript 中链接到的其他资源(如图像、视频或字体文件)的获取也可能导致性能问题,阻塞代码的执行并减慢体验速度。一种缓解此类问题的方法是使用 rel="preload" 将 <link>
元素转换为预加载器。
遇到 rel="preload" 链接时,浏览器将尽快获取所引用的资源,并使其在浏览器缓存中可用,以便在后续代码中引用时更快地准备好。预加载用户在页面浏览早期会遇到的高优先级资源非常有用,这样可以让用户获得尽可能流畅的体验。