多年来,web 社区积累了丰富的 web 性能优化知识。虽然任何一项优化都可能提高许多网站的性能,但所有优化同时进行可能会让人感到难以承受,而且实际上,其中只有一部分适用于任何给定的网站。
除非 web 性能是您的日常工作,否则哪些优化对您的网站影响最大可能并不明显。您可能没有时间进行所有优化,因此重要的是要问自己您可以选择哪些影响最大的优化来提高用户性能?
以下是关于性能优化的真相:您不能仅凭其技术优点来判断它们。您还需要考虑影响您实施任何给定优化的可能性的人为和组织因素。一些性能改进在理论上可能影响巨大,但实际上,很少有开发人员有时间和资源来实施它们。另一方面,可能存在影响巨大的性能最佳实践,几乎每个人都已经遵循。本指南确定了以下 web 性能优化:
- 具有最大的实际影响
- 与大多数网站相关且适用
- 对于大多数开发人员来说,实施起来是现实的
总而言之,这些是您可以提高 Core Web Vitals 指标的最现实且影响最大的方法。如果您是 web 性能新手,或者您仍在决定什么将为您带来最大的投资回报,那么这里是最佳起点。
Interaction to Next Paint (INP)
作为最新的 Core Web Vital 指标,Interaction to Next Paint (INP) 具有一些最大的改进机会。但是,由于与已弃用的前身相比,通过“良好”体验阈值的网站要少得多,因此您可能是众多首次学习如何优化交互响应性的开发人员之一。从这些必须知道的技巧开始,以了解提升 INP 的最有效方法。
1. 经常让步以分解长任务
任务是浏览器执行的任何离散工作,包括渲染、布局、解析、编译或执行脚本。当任务持续时间超过 50 毫秒时,它将成为长任务。长任务存在问题,因为它们会阻止主线程快速响应用户交互。
虽然您应该始终努力在 JavaScript 中尽可能少地完成工作,但您可以通过分解长任务来帮助主线程。您可以通过经常让步于主线程来实现这一点,以便渲染更新和其他用户交互可以更快地发生。
Scheduler API 允许您使用优先级系统对工作进行排队。具体来说,scheduler.yield() API 会分解长任务,同时确保可以处理交互而不会放弃其在任务队列中的位置。
通过分解长任务,您为浏览器提供了更多机会来适应关键的、阻止用户的工作。
2. 避免不必要的 JavaScript
网站正在运送比以往任何时候都多的 JavaScript,而且这种趋势似乎没有改变。当您运送过多的 JavaScript 时,您正在创建一个环境,其中任务正在争夺主线程的注意力。这可能会影响您网站的响应速度,尤其是在关键的启动期间。
但是,这不是一个无法解决的问题,您有以下选择
- 使用 Baseline 广泛可用的 web 平台功能,而不是冗余的、基于 JavaScript 的实现。
- 使用 Chrome DevTools 中的 覆盖率工具来查找脚本中未使用的代码。通过减少启动期间所需的资源大小,您可以确保页面花费更少的时间来解析和编译代码,从而提供更流畅的初始用户体验。
- 使用 代码拆分为初始渲染不需要但稍后仍将使用的代码创建单独的捆绑包。
- 如果您正在使用标签管理器,请定期优化您的标签。可以删除具有未使用代码的旧标签,以减少标签管理器的 JavaScript 占用空间。
3. 避免大型渲染更新
JavaScript 执行只是影响您网站响应速度的一个因素。渲染本身就是一种昂贵的工作类型,在大型渲染更新期间,您的网站对用户交互的响应速度可能会更慢。
优化渲染工作不是一个简单的过程,这取决于您想要实现的目标。即便如此,您仍然可以做一些事情来确保渲染任务不会变成长任务
- 在您的 JavaScript 代码中重新组织 DOM 读取和写入,以避免强制布局和布局抖动。
- 保持 DOM 大小较小。DOM 大小和布局工作的强度是相关的。当渲染器必须更新非常大的 DOM 的布局时,重新计算其布局所需的工作量可能会显着增加。
- 使用 CSS 内容可见性来延迟渲染屏幕外 DOM 内容。这并非总是简单直接,但通过隔离包含复杂布局的区域,您可以避免不必要的布局和渲染工作。
Largest Contentful Paint (LCP)
Largest Contentful Paint (LCP) 是开发人员往往最难处理的 Core Web Vital 指标——Chrome UX 报告中40% 的网站不符合良好用户体验的建议 LCP 阈值。Chrome 团队建议以下技术是提高 LCP 的最有效方法。
1. 确保 LCP 资源可从 HTML 源代码中发现并优先处理
Chrome 团队注意到了以下关于 web 上 LCP 的情况
- 根据 HTTP Archive 的 2024 Web Almanac,73% 的移动页面使用图像作为其 LCP 元素。
- 对来自 Chrome 的真实用户数据的分析表明,LCP 较差的大多数来源在 p75 LCP 时间中不到 10% 的时间用于下载 LCP 图像。
- 在 LCP 较差的页面中,在 75% 的百分位,客户端延迟加载 LCP 图像的时间为 1,290 毫秒——这超过了快速体验预算的一半。
- 在 LCP 元素为图像的页面中,35% 的这些图像的源 URL 在初始 HTML 响应中不可发现(例如
<img src="...">
或<link rel="preload" href="...">
),这将允许浏览器的预加载扫描器尽快发现它们。 - 根据 Web Almanac,15% 的符合条件的页面正在利用
fetchpriority
HTML 属性来为资源(包括那些可以相对轻松地改进页面 LCP 的资源)提供更高的优先级。
这些统计数据表明,开发人员有很大的机会来减少 LCP 图像的资源加载延迟和资源加载持续时间。
如果资源加载延迟是问题所在,那么至关重要的是要记住,如果页面需要等待 CSS 或 JavaScript 完全加载后图像才能开始加载,那么实现良好的 LCP 可能已经为时已晚。此外,可以通过重新调整 LCP 图像的优先级来减少其资源加载持续时间,使其获得更多带宽,从而使用 fetchpriority
HTML 属性更快地加载。
如果您的 LCP 元素是图像,则图像的 URL 应在 HTML 响应中可发现,以减少其资源加载延迟。使之成为可能的提示包括:
- 使用带有
src
或srcset
属性的<img>
元素加载图像。 不要使用非标准属性,例如data-src
,这些属性需要 JavaScript 才能渲染,因为这总是会更慢。7% 的页面将其 LCP 图像隐藏在data-src
后面。 - 首选服务器端渲染 (SSR) 而不是客户端渲染 (CSR), 因为 SSR 意味着完整的页面标记(包括图像)都存在于 HTML 源代码中。CSR 解决方案需要 JavaScript 才能运行,然后才能发现图像。
- 如果您的图像需要从外部 CSS 或 JS 文件引用,您仍然可以使用
<link rel="preload">
标签将其包含在 HTML 源代码中。 请注意,浏览器的预加载扫描器无法发现内联样式引用的图像,因此即使在 HTML 源代码中找到它们,它们的发现仍可能被其他资源的加载所阻止,因此在这些情况下预加载会有所帮助。
此外,您可以通过确保 LCP 资源尽早且以高优先级加载来缩短资源的加载持续时间
- 将
fetchpriority="high"
属性添加到 LCP 图像的<img>
或<link rel="preload">
标签中。 这会提高图像资源的优先级,使其能够更快地开始加载。 - 从 LCP 图像的
<img>
标签中删除loading="lazy"
属性。 这避免了因确认图像是否出现在视口中或附近而导致的加载延迟。 - 尽可能延迟非关键资源。 将这些资源移动到文档末尾、延迟加载图像或 iframe,或使用 JavaScript 异步加载它们将有助于为更重要的资源(如 LCP 图像)更快地加载让路。
2. 力求实现即时导航
理想的用户体验是永远不必等待页面加载。像资源可发现性和优先级排序这样的 LCP 优化可以有效地减少用户等待 LCP 元素加载和渲染的时间——但是,通过网络加载这些字节并在页面上渲染的速度存在物理限制。在您达到该限制之前,仅削减几毫秒所需的工作量就非常高。因此,为了实现即时导航,我们需要采取截然不同的方法。
即时导航尝试在用户开始导航到页面之前加载和渲染页面。这样,预渲染的页面可以立即显示,LCP 几乎为零。恢复和推测是实现此目的的两种方法。当用户向后或向前导航到先前访问的页面时,可以从内存缓存中快速恢复该页面,使其外观与用户离开时完全相同。或者,web 应用程序可以尝试预测用户接下来将访问哪里——如果预测正确,则当用户导航到该页面时,下一页将已经加载和渲染完毕。
通过后退/前进缓存 (bfcache),可以恢复先前访问的页面。要使用它,您必须确保您的页面符合 bfcache 资格标准。页面不符合 bfcache 资格的常见原因是它们使用 no-store
缓存指令提供服务,或者具有 unload
事件侦听器。
恢复完全渲染的页面不仅可以提高加载性能,还可以提高布局稳定性。您可以在确保页面符合 bfcache 资格部分中了解有关 bfcache 及其提高 CLS 效果的更多信息。
预渲染用户访问的下一页是显着提高 LCP 性能的另一种有效方法,并且可以通过 Speculation Rules API 实现。但是,要实现这些收益,请确保预渲染正确的页面。不正确的推测会浪费服务器和客户端上的资源,这可能会损害性能。因此,您对下一页是什么越不确定,您就应该越保守地预渲染它。如有疑问,您的分析数据可以让您更有信心地更积极地预渲染最有可能在接下来访问的页面。
3. 使用 CDN 优化 TTFB
之前的建议侧重于即时导航,这为用户提供了最佳的体验,但在某些情况下,bfcache 和推测性加载技术可能不适用。考虑用户跟踪跨域链接到您的网站,其中初始 HTML 文档响应有效地阻止了 LCP。浏览器在收到响应的第一个字节之前无法开始加载任何子资源。这种情况发生得越早,其他一切才能越早开始发生。
这个时间称为 Time to First Byte (TTFB)。减少 TTFB 的最佳方法是:
- 尽可能在地理位置上靠近用户的位置提供您的内容。
- 缓存该内容,以便在不久的将来再次请求时可以快速提供。
执行这两项操作的最佳方法是使用 CDN。CDN 将您的资源分发到全球各地的边缘服务器,从而限制了这些资源必须通过网络传输到用户的距离。CDN 通常还具有可以针对您网站的需求进行调整的细粒度缓存控制。
CDN 还可以提供和缓存 HTML 文档,但根据 Web Almanac,只有 33% 的 HTML 文档请求是从 CDN 提供的。这意味着网站有很大的机会实现额外的节省。
配置 CDN 的一些技巧包括:
- 即使是很短的时间,也要缓存静态 HTML 文档。例如,内容始终保持新鲜是否重要?还是可以过时几分钟?
- 探索是否可以将源服务器上运行的动态逻辑移动到边缘,这是大多数现代 CDN 的一项功能。
任何时候,当您可以直接从边缘提供内容并避免访问源服务器时,都是性能的胜利。即使在您确实必须一直访问源服务器的情况下,CDN 通常也经过优化以更快地完成此操作,因此无论哪种方式,这都是一场胜利。
Cumulative Layout Shift (CLS)
Cumulative Layout Shift (CLS) 是衡量网页视觉稳定性的指标。虽然 CLS 是大多数网站往往做得不错的指标,但大约有四分之一的网站仍然不符合建议的阈值,因此许多网站仍然有很大的机会来改善其用户体验。
1. 为页面加载的任何内容设置显式大小
布局偏移通常发生在其他内容完成加载后现有内容移动时。改进 CLS 的主要方法是尽可能提前预留所需的空间。
修复由未调整大小的图像引起的布局偏移的最佳方法是显式设置 width
和 height
属性或其等效的 CSS 属性。66% 的页面至少有一个未调整大小的图像。如果没有显式大小,这些图像的初始高度为 0px
,这可能会在这些图像加载并且浏览器发现其尺寸时导致布局偏移。这代表了整个 web 的巨大机会,并且这种机会所需的工作量比本指南中建议的其他一些建议要少。
图像不是 CLS 的唯一贡献者。布局偏移可能是由其他通常在页面初始渲染后加载的内容引起的,包括第三方广告或嵌入式视频。aspect-ratio
属性可以帮助解决此问题。它是一个 Baseline 广泛可用的 CSS 功能,允许开发人员在图像以及非图像元素上显式设置纵横比。这使您可以设置动态 width
(例如,基于屏幕尺寸),并让浏览器自动计算适当的高度,这与具有尺寸的图像的处理方式非常相似。
但是,有时不可能知道动态内容的确切大小。即使您不知道确切的大小,您仍然可以降低布局偏移的严重性。设置合理的 min-height
几乎总是比允许浏览器为空元素使用默认高度 0px
更好。使用 min-height
通常也是一个简单的修复方法,因为它仍然允许容器增长到最终内容的高度(如果需要)——它只是将增长量降低到希望更可接受的水平。
2. 确保页面符合 bfcache 资格
如本指南前面所述,后退/前进缓存 (bfcache) 从内存快照中即时加载浏览器历史记录中较早或较晚的页面。虽然 bfcache 是一项重要的浏览器级性能优化,可以改善 LCP,但它也完全消除了布局偏移。事实上,2022 年 bfcache 的引入是我们在当年看到的 CLS 最大改进的原因。
尽管如此,大量网站仍然不符合 bfcache 的条件,因此错失了这项免费的网络性能提升。除非您的页面加载了您不希望从内存中恢复的敏感信息,否则请确保您的页面符合使用 bfcache 的条件。
网站所有者应检查页面是否符合 bfcache 的条件,并修复导致不符合条件的任何原因。Chrome 在 DevTools 中有一个 bfcache 测试器,您还可以使用 Not Restored Reasons API 来检测现场不符合条件的原因。
3. 避免使用会引起布局重排的 CSS 属性的动画和过渡效果
布局偏移的另一个常见来源是元素动画。例如,从顶部或底部滑入的 Cookie 横幅或其他通知横幅通常会导致 CLS。当这些横幅将其他内容挤出时,问题尤其严重,但即使它们不这样做,动画化它们仍然会影响 CLS。
虽然 HTTP Archive 数据无法最终将动画与布局偏移联系起来,但数据显示,与总体页面相比,对任何可能影响布局的 CSS 属性进行动画处理的页面,“良好” CLS 的可能性降低了 15%。一些属性与比其他属性更差的 CLS 相关。例如,动画化 margin
或 border
宽度的页面出现“差” CLS 的比率几乎是总体页面被评估为差的两倍。
这也许并不令人惊讶,因为任何时候您过渡或动画化任何会引起布局重排的 CSS 属性,都会导致布局偏移。如果这些布局偏移不是在用户交互的 500 毫秒内发生的,它们将影响 CLS。
一些开发者可能会感到惊讶的是,即使在元素被移出正常文档流的情况下,情况也是如此。例如,即使绝对定位的元素没有推开其他内容,动画化 top
或 left
也会导致布局偏移。但是,如果动画化 transform:translateX()
或 transform:translateY()
而不是动画化 top
或 left
,则不会导致浏览器更新页面布局,从而避免布局偏移。
首选在浏览器的合成器线程上更新的 CSS 属性的动画,长期以来一直是性能最佳实践,因为它将该工作从主线程转移到 GPU。除了它是一般的性能最佳实践之外,它还可以帮助改进 CLS。
作为一般规则,除非您是为了响应用户的点击或按键(尽管不是 hover
),否则永远不要动画化或过渡需要浏览器更新页面布局的 CSS 属性。在可能的情况下,首选使用 CSS transform
属性的过渡和动画。
避免非合成动画 Lighthouse 审核会在页面动画化可能较慢的 CSS 属性时发出警告。
结论
提高页面性能似乎令人生畏,尤其是在考虑到网络上有大量的指导需要考虑的情况下。但是,通过专注于这份最有效的最佳实践的简短列表,您可以以新的重点来处理问题,并有望为您的网站的核心网页指标带来改进。
如果您想超越此处列出的优化,请阅读以下指南以获取更多信息
附录:变更日志
本文档的重大更改将在此处跟踪,以帮助解释顶级建议何时以及为何发生更改。
2024 年 10 月
2024 年更新
- INP
- 我们根据 INP 作为核心网页指标的发布将此指标从 FID 切换到 INP,并使其成为列表中的首要指标。
- 我们撤销了关于使用
isInputPending
API 作为分解长任务一部分的建议。您可以在优化长任务文章中了解有关我们理由的更多信息。
- LCP
- 我们将可发现性和优先级建议合并为一个。
- 我们添加了一项旨在实现即时导航的新建议。
2023 年 1 月
这是最初的建议列表
- LCP
- 确保 LCP 资源可从 HTML 源代码中发现
- 确保 LCP 资源被优先处理
- 使用 CDN 来优化文档和资源 TTFB
- CLS
- 为从页面加载的任何内容设置显式尺寸
- 确保页面符合 bfcache 的条件
- 避免使用会引起布局重排的 CSS 属性的动画和过渡效果
- FID
- 避免或分解长任务
- 避免不必要的 JavaScript
- 避免大型渲染更新
您还可以观看此 2023 Google I/O 演示文稿以获取视频摘要。