First Contentful Paint
通过加速 First Contentful Paint 来改善 Core Web Vitals
修复 First Contentful Paint - 简述
First Contentful Paint (FCP) 是浏览器在页面上为访问者绘制第一个有意义元素的时刻。换句话说,它是浏览器首次在屏幕上渲染内容的时刻。因此,FCP 是衡量感知页面加载速度的一个好方法。
你可以通过确保浏览器能够无延迟地开始渲染来改善 FCP。我将解释这是什么以及如何做到这一点。
什么是 First Contentful Paint (FCP)?
First Contentful Paint (FCP) 是一种衡量页面加载速度的方法。你无法将页面速度概括为一个时间点,在加载过程中实际上有多个时刻,访问者可能会觉得网站加载得快或慢。FCP 衡量的是从请求页面到第一个有意义的内容首次渲染到屏幕上之间的时间差。
这究竟能告诉你什么呢?它说明 FCP 主要是一个"以用户为中心的指标",因为它反映了访问者所感受到的加载速度。它体现了 user experience。在 FCP 时刻,你可以确定访问者实际上在屏幕上看到了"某些内容"。
让我们拆解一下这几个词:'First'、'Contentful' 和 'Paint'。
- First: First 当然是指浏览器上首次出现实质性内容的确切时刻。
- Contentful:Contentful 指的是带有内容的 HTML 元素。不是像空白元素或背景颜色这样的布局元素,而是一些文本、图片(包括背景图片)、SVG 或 canvas。
- Paint:Paint 的意思(大致上)是浏览器准备好在屏幕上放置内容。这看起来很简单,但实际上这是浏览器最复杂的任务。为了在屏幕上放置内容,浏览器必须准备好计算元素的所有特性。下面是一个渲染过程的示例,在任何内容被添加到屏幕之前都需要完成这个过程。
什么是好的 First Contentful Paint 分数?
良好的 FCP 分数是 0 到 1.8 秒之间的任何值。如果你的 FCP 分数在 1.8 到 3 秒之间,则需要改进。任何超过 3 秒的 FCP 分数都被认为是较差的。要通过 Largest Contentful Paint 的 Core Web Vitals 评估,至少 75% 的访问者需要拥有"良好"的 FCP 分数。

与 Core Web Vitals 一贯的标准一样,First Contentful Paint 分数越快越好。
如何衡量你的 First Contentful Paint (FCP)?
FCP 由 Google 通过收集真实用户数据来衡量。该数据存储在 CrUX 数据集中。该数据可通过 CrUX API 或 Google BigQuery 公开获取。FCP 也可以通过所谓的实验室测试来衡量。最常见的实验室测试称为 Lighthouse。
从 CrUX 数据集获取 First Contentful Paint
First Contentful Paint 可以通过 pagespeed.web.dev、CrUX API 或 Google BigQuery 从 CrUX 数据集中读取。
通过 Real User Monitoring (RUM) 衡量 First Contentful Paint
RUM Tracking 代表 Real User Monitoring。通过 Real User Monitoring,你可以通过真实用户交互来跟踪 First Contentful Paint。RUM Tracking 的优势在于你不必等待 28 天获取新数据,并且数据可以以更详细的方式进行查询和分析。
在 Lighthouse 中衡量 FCP
- 在 Chrome 中打开你想要衡量 FCP 的页面。确保在无痕模式下进行,这样插件不会干扰你并可能减慢页面的 FCP。
- 右键点击页面并选择"检查元素"。这样就可以打开 Chrome 开发者控制台。
- 在控制台顶部,你会看到 Lighthouse 标签。点击它。然后在"类别"下选择"性能"(其他留空),在"设备"下选择"移动设备"。
- 现在点击"生成报告"。Lighthouse 将为你的页面创建一个速度报告。在报告的左上角,你会看到页面的 FCP 是多少。

这是本页面的 Lighthouse 报告截图。该页面在移动设备上的 FCP 为 0.8 秒!还不错吧?
使用在线工具衡量 FCP
你也可以使用多种在线工具来衡量 FCP。最知名的是 GTMetrix、pingdom 和 pagespeed.web.dev。这些工具易于使用,可以在特定的实验室条件下提供有关 LCP 的一些数据。
改善 First Contentful Paint
既然你已经知道了 First Contentful Paint 是什么,我们就可以着手让它变得更快。快速 FCP 背后的理念其实很简单:确保浏览器能够立即开始渲染。任何可能导致渲染延迟的因素都会导致较差的 FCP 分数。
与 Largest Contentful Paint 一样,First Contentful Paint 可以分解为 2 或 4 个类别:
- Time to First Byte (TTFB) - 从页面开始加载到浏览器接收到第一个 HTML 字节之间的时间。
- 资源加载延迟 - 从 TTFB 到浏览器开始加载 FCP 资源之间的时间
- 资源加载时间 - 加载 FCP 资源本身所需的时间。
- 元素渲染延迟 - 从 FCP 资源加载完成到 LCP 元素完全渲染之间的时间
速度提示:你可以通过确保 LCP 元素不需要网络资源来轻松消除第 2 和第 3 步。对于文本元素,考虑使用 font-display:swap。对于小图片元素,考虑将图片内联放置。
这样我们只剩下 Time to First Byte 和元素渲染延迟需要优化。
以下是我经常用来改善 FCP 的 14 个解决方案。但要小心,在错误的地方使用解决方案实际上可能会造成延迟。这就是为什么最好在开始之前咨询页面速度专家。
1. 快速服务器响应 (TTFB)
TTFB(从请求到服务器发送第一个字节之间的时间)始终是渲染过程的第一步。从那时起,你的浏览器开始多任务处理,进一步优化的影响开始递减。HTML 代码是唯一直接影响所有速度指标的请求。
服务器发送 HTML 代码的速度通常用 Time to First Byte (TTFB) 来衡量。尽可能快地完成这一点非常重要。通常你可以通过启用服务器端缓存来实现。
当涉及到 Time to First Byte 时,越低越好。

你可以自己轻松衡量 Time to First Byte。方法如下:
- 使用快捷键 Ctrl-Shift-I 打开 Google Chrome 的开发者控制台。
- 在控制台顶部,你会看到一个"网络"标签。点击它。
- 通过 Ctrl-R 重新加载页面。
- 你现在会看到 Chrome 发送到服务器的所有网络请求。
- 点击最上面的网络请求,即页面本身的请求。
- 现在你将获得有关该网络请求的更多信息。 点击该信息顶部的"时间"标签,查看页面的 TTFB。
2. HTTP/3
HTTP/3 是 HTTP 协议的第三个版本。HTTP/3 解决了旧版 HTTP/1.1 和 HTTP/2 协议中发现的许多问题。例如,自 HTTP/2 以来,你可以通过同一连接同时发送多个文件。HTTP/3 提供了更快的初始连接,并且减少了轻微网络中断带来的问题。
不深入太多细节,HTTP/3 可以带来显著的速度提升,特别是在较慢的网络上,如移动网络。你的网络管理员可以告诉你,你的 Web 服务器是否已经适配了更快的 HTTP/3 协议。

你可以自己检查你的网站是否已经在使用更快的 HTTP/3 协议。使用快捷键 Ctrl-Shift-I 打开 Google Chrome 的网络检查器。右键点击表头并选择"协议"。现在重新加载页面,查看你的网站正在使用什么协议。
3. 浏览器缓存
在页面速度方面,网络连接通常是一个薄弱环节。如果能完全跳过网络,那不是容易得多吗?
当访问者之前访问过你的网站时,你可以指定网络资源 (例如样式表) 是否以及可以存储多长时间在访问者的浏览器中。每当访问者再次需要这些文件时,它们会立即从浏览器缓存中弹出。因此,浏览器可以更快地开始渲染,从而加速 FCP。

4. 压缩
在几乎所有情况下,网络速度都是一个薄弱环节。对于良好的 First Contentful Paint 来说,文件通过网络尽快发送非常重要。压缩减少了必须从服务器发送的字节数——更少的字节意味着更少的网络资源等待时间。在我看来,压缩是一种没有得到应有关注的技术。不幸的是,太多站长"打开压缩"后就再也不看了。这很可惜,因为它只是一种让事情变得更快一点的简单方法。
有两种流行的压缩技术:Gzip 和 Brotli。Gzip 是最常用的压缩技术,但 Brotli 正在迅速赶上。Brotli 由 Google 自己创建,在 HTML、JavaScript 或 CSS 文件方面有 15% 到 20% 的更好结果。因此,Brotli 非常适合 Web。
动态压缩和静态压缩之间也有区别。动态压缩是在通过 Web 服务器发送文件之前压缩文件;静态压缩是将压缩后的文件存储在服务器上。这通常是一种更聪明的压缩方式,但很少被使用。
5. 使用资源提示提前加载 Web 字体
资源提示会在浏览器自行下载或建立网络连接之前启动下载或网络连接。某些网络资源,如 Web 字体或图片,只有在浏览器确定需要显示它们之后才会被下载。
如果你确定需要某个资源来渲染网站的可见部分,那么添加"资源提示"几乎总是一个好主意。这将确保浏览器立即开始下载或连接到该资源。因此,资源会更快可用,浏览器可以更早开始渲染。
但要小心使用资源提示,如果使用不当,它们实际上可能会减慢你的页面速度。
使用 "preloading" 提前下载
<link rel="preload" href="/static/font/opensans600.woff2" as="font" type="font/woff2" crossorigin>
preload 链接是页面速度工具库中最强大的工具之一。通过 preload 链接,你可以下载稍后需要的网络资源。这对于字体、关键脚本和网站可见部分的图片通常是非常好的做法。
使用 preconnect 提前连接
preconnect 链接会提前连接到服务器。当你在第三方服务器上托管文件(如 CDN 或 Google analytics)时,这很有用。
<link rel="preconnect" href="https://fonts.googleapis.com"> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
6. 使用 prefetch 预取下一个页面
<link rel="prefetch" href="/page2.html">
使用 prefetch,你可以获取低优先级资源。当你认为稍后会需要某些资源时,这是一种有用的方式——例如,当你预期某人会点击下一页链接时。
7. 避免重定向
一个常见的错误是重定向链过长。让我解释一下:你的网站可能通过安全连接运行。当访问者输入你的网站地址而没有添加 https 时,他将被重定向到你网站的非安全版本。然而,如果一切设置正确,访问者将被重定向到安全网站。你可以在下面的绿色示例中看到这一点。
但有时重定向会通过一个或多个中间步骤进行,如红色示例所示。正是这些中间步骤导致网站运行缓慢,从而导致较差的 First Contentful Paint 分数。每个中间步骤都会花费额外的时间,这些时间可以迅速累积。因此,始终确保在一次重定向内到达正确的页面。

8. 最小化 CSS
外部 CSS 文件始终是渲染阻塞的。这意味着浏览器通常在所有样式表下载和分析完成之前无法开始显示内容。因此,最好将样式表保持尽可能小。这样你就不必等待太长时间来下载样式表。
使用简写代码减小 CSS 大小
减小 CSS 大小的方法之一是使用简写代码。这些单行代码允许你将 CSS 选择器最重要的属性写在一行中。
body{
font-style: normal;
font-weight: 400;
font-stretch: normal;
font-size: 0.94rem;
line-height: 1.6;
font-family: "Segoe UI", "Segoe UI", system-ui, -apple-system, sans-serif;
}
也可以写成:
body{font: 400 .94rem/1.6 Segoe UI,Segoe UI,system-ui,-apple-system, sans-serif;}
进一步减小 CSS 大小
可以通过合并选择器(用逗号分隔)、删除换行和空格以及使用更短的颜色代码来进一步减小 CSS 大小。
h1{
color : #000000;
}
h2{
color : #000000;
}
h3{
color : #000000;
}
h4{
color : #000000;
}
h5{
color : #000000;
}
可以缩短为
h1,h2,h3,h4,h5{color:#000}
9. 关键 CSS
我们可以更进一步使用关键 CSS。关键 CSS 是快速网站和快速 First Contentful Paint 的必备技术。
关键 CSS 是显示页面可见部分所需的所有选择器(如 body、p、h1 等)的集合。不要将这些关键 CSS 放在单独的样式表中;而是直接将其添加到页面的 <head> 中。这样你就不必下载新文件,浏览器可以以闪电般的速度开始渲染。这将带来更快的 FCP。页面可见部分不直接需要的 CSS 在第一个渲染周期完成后加载。对访问者来说,页面已经完成了——没有人会注意到新样式仍在后台添加。
关键 CSS 可以使用我们自己的 关键 CSS 工具轻松生成。只需将你的网页 URL 粘贴到工具中,我们会为你完成其余工作!

10. 延迟加载 JavaScript
First Contentful Paint 缓慢的最常见原因之一是 JavaScript。根据你使用 JavaScript 的方式,它可能会阻塞页面的渲染。通常 JavaScript 在构建渲染树之前会被下载和执行。没有渲染树,浏览器就无法在屏幕上放置任何内容——这包括 FCP。

我们可以通过推迟 JavaScript 来解决这个问题。你可以通过三种方式做到这一点
异步 JavaScript
<script async src="async.js"></script>
通过向 script 标签添加 async 属性,JavaScript 下载期间页面的构建不再被阻塞。async 属性表示下载和渲染树的构建可以同时进行。
脚本执行后,页面会被阻塞。在大多数情况下,由于 async 属性,浏览器已经有足够的时间构建页面的重要部分,First Contentful Paint 已经显示在页面上。
延迟 JavaScript
<script defer src="async.js"></script>
defer 属性的工作方式与 async 属性大致相同。通过向 script 标签添加 defer 属性,脚本也可以在构建页面的同时下载。所有脚本下载完成后,它们将按照在 HTML 代码中被找到的顺序执行。这也可能阻塞页面的显示,但在许多情况下,First Contentful Paint 已经显示在屏幕上。
11. 不要依赖外部资源
外部资源,如外部字体、外部图片、外部样式表或外部脚本,在 First Contentful Paint 方面是一个潜在的瓶颈。由于你无法控制文件所在的服务器,你不知道它们将以多快的速度发送。此外,你无法使用与 Web 服务器的现有连接。必须建立到新服务器的新连接——这需要时间。
阻塞的外部资源
无外部资源
12. 使用正确的字体格式
在 First Contentful Paint 方面,字体值得特别关注。在我们查看的大约 99% 的页面中,FCP 元素是一行文本。当你使用外部 Web 字体时,你需要先从服务器下载这些字体,这当然需要时间。
最近,Web 字体越来越受到关注,也有更多新的、更快的字体格式。目前最快的字体格式是 woff2,其次是 woff。Woff2 被每个现代浏览器支持。
你可以在 CSS font-face 声明中指定 Web 字体的首选顺序。方法如下:
@font-face {
font-family: 'myFont';
font-weight: 400;
font-style: normal;
font-display: swap;
unicode-range: U+000-5FF
src: local('myFont'),
url('/fonts/myFont.woff2') format('woff2'),
url('/fonts/myFont.woff') format('woff');
}
13. Font display:swap
使用 Web 字体时,这些字体的默认行为是在字体加载完成之前不显示页面上的文本。这通常直接影响 First Contentful Paint。
你可以通过使用 font-display:swap 来解决这个问题。这样你可以选择在 Web 字体在后台加载时,使用浏览器已知的字体在页面上显示文本。
不使用 font-display:swap
使用 font-display:swap
阅读我们的完整文章 Ensure text remains visible during webfont load
14. 最小化 DOM 大小
网页由 HTML 组成。浏览器做的第一件事是将 HTML 转换为 DOM 节点。这是一个 HTML 元素的树状结构,稍后用于构建渲染树。浏览器从渲染树开始渲染;最终网页出现在屏幕上。
你拥有多少 DOM 节点(HTML 元素)以及这些 DOM 节点在树状结构中的深度决定了浏览器构建页面的复杂程度。当你有太多 DOM 节点时,CSS 和 JavaScript 的分析也会花费更多时间。这再次直接影响 FCP。
解决方法:
- 懒加载网页的部分内容
为了加速初始显示,考虑在稍后通过 AJAX 加载网站的部分内容,如页脚。 - 使用 content-visibility
CSS 属性 content-visibility 告诉浏览器在渲染期间跳过样式、布局和绘制。它在元素即将变为可见之前执行此操作。 - 将大页面拆分为多个页面
可以通过将大页面拆分为多个页面来减少 DOM 节点的数量。 - 实现无限滚动
无限滚动基本上就是懒加载:当滚动浏览重复元素(如图片(pinterest)或大型数据表)时,无限滚动可以显著加快页面速度。 - 避免 JavaScript DOM 交互
当页面上有大量 DOM 节点时,要特别注意 JavaScript。这样的命令可能会加载大量 DOM 节点,增加内存使用。 - 避免复杂的 CSS 声明
当有大量 DOM 节点时,要特别注意复杂的 CSS 命令。例如,你需要检查页面上每个 div 元素的 last-child 状态。 - 使用 Web workers 来减轻浏览器主线程的负担
Web workers 是可以与网页并行运行的 JavaScript。你可以给这些 Web workers 命令,让它们在后台执行。当 Web worker 执行完命令后,它会将结果传递给原始页面。这样做的好处是你仍然可以执行复杂的 JavaScript 而不会导致页面冻结。
Stop debating in Jira.
Get a definitive answer on your performance issues. I deliver a granular breakdown of your critical rendering path.
- Definitive Answers
- Granular Breakdown
- Critical Path Analysis