打开 Lighthouse 或 Chrome DevTools 的 Performance 面板时,我们经常会看到 FCP、LCP、CLS、TBT、INP 等缩写。它们并不是在重复衡量同一件事,而是分别回答几个不同的问题:页面多久出现内容、主要内容多久加载完成、页面是否稳定,以及用户操作后多久得到反馈。
本文将逐一介绍这五个指标,并说明它们之间的关系和常见优化方向。
一、FCP:页面什么时候不再白屏
FCP(First Contentful Paint,首次内容绘制)表示浏览器第一次在页面中绘制有效内容的时间。这里的内容可以是文字、图片、SVG 或 Canvas,而纯背景色变化通常不算有效内容。
FCP 关注的是用户什么时候第一次看到页面内容。它并不代表页面已经加载完成,只表示页面不再是一片空白。
FCP 的参考标准
- 良好:不超过 1.8 秒
- 需要改进:1.8~3 秒
- 较差:超过 3 秒
FCP 过慢的常见原因
- 服务器响应时间过长
- HTML 返回较慢
- CSS 或同步 JavaScript 阻塞渲染
- 首屏依赖的资源过多、体积过大
- 页面完全依赖客户端 JavaScript 生成内容
常见优化方式
- 使用 CDN、缓存和服务端压缩降低资源传输时间
- 减少阻塞渲染的 CSS 和 JavaScript
- 内联首屏关键 CSS,延迟加载非关键样式
- 对页面进行 SSR 或 SSG,避免首屏长期等待客户端渲染
- 减少重定向和不必要的第三方脚本
二、LCP:主要内容什么时候呈现
LCP(Largest Contentful Paint,最大内容绘制)表示视口内最大的内容元素完成绘制的时间。这个元素通常是首屏 Banner、大图、视频封面、文章标题或一大段文本。
与 FCP 相比,LCP 更接近用户对“页面主要内容是否已经加载出来”的感受。FCP 很快并不一定意味着体验良好,例如页面先显示一个很小的加载图标,但主图几秒后才出现,此时 FCP 很快,LCP 仍然很慢。
LCP 的参考标准
- 良好:不超过 2.5 秒
- 需要改进:2.5~4 秒
- 较差:超过 4 秒
LCP 可以拆成哪些阶段
分析 LCP 时,可以从以下几个阶段定位问题:
- 首字节时间:服务器开始返回文档用了多久
- 资源加载延迟:浏览器多久发现并开始请求 LCP 资源
- 资源加载耗时:图片、字体等资源下载用了多久
- 元素渲染延迟:资源下载后多久真正显示到页面上
常见优化方式
- 压缩首屏图片并使用 WebP、AVIF 等现代格式
- 为 LCP 图片设置较高请求优先级,例如
fetchpriority="high" - 必要时使用
preload提前加载关键图片或字体 - 不要对首屏 LCP 图片使用懒加载
- 降低服务器响应时间
- 减少主线程阻塞,避免资源已加载却迟迟无法渲染
三、CLS:页面内容是否稳定
CLS(Cumulative Layout Shift,累计布局偏移)衡量页面在生命周期内发生的意外布局移动。它关注的不是速度,而是视觉稳定性。
例如,用户正准备点击一个按钮,顶部图片突然加载并把按钮向下挤;或者广告加载后插入页面,使正文整体跳动。这些都会产生布局偏移,并增加 CLS。
CLS 是一个分数,没有秒或毫秒单位。浏览器会把相邻时间窗口内发生的布局偏移归为一组,并使用得分最高的一组作为 CLS 结果,而不是简单地把页面生命周期中的所有偏移无限累加。
CLS 的参考标准
- 良好:不超过 0.1
- 需要改进:0.1~0.25
- 较差:超过 0.25
CLS 过高的常见原因
- 图片、视频或 iframe 没有预留宽高
- 广告和异步模块加载后直接插入已有内容上方
- Web Font 加载后字体尺寸发生明显变化
- 动态内容改变了已有元素的布局
- 使用会触发布局变化的动画属性
常见优化方式
- 为图片和视频声明
width、height或aspect-ratio - 为广告、推荐位和异步模块预留固定或最小空间
- 优化字体加载,并选择尺寸接近的回退字体
- 尽量在已有内容下方插入动态内容
- 动画优先使用
transform和opacity
需要注意的是,由用户操作直接触发并在较短时间内发生的合理布局变化,通常不会被视为意外偏移。例如用户点击“展开详情”后内容展开,一般不属于需要消除的 CLS 问题。
四、TBT:主线程被阻塞了多久
TBT(Total Blocking Time,总阻塞时间)用于衡量页面加载阶段主线程无法及时响应用户操作的总时长,是 Lighthouse 性能评分中的重要实验室指标。
浏览器主线程上的单个任务超过 50 毫秒时,会被视为长任务。超过 50 毫秒的部分才计入阻塞时间。例如一个任务执行了 120 毫秒,它对 TBT 的贡献是:
120ms - 50ms = 70ms
Lighthouse 会累计 FCP 之后到页面可交互阶段之间所有长任务的阻塞部分,得到 TBT。
TBT 的参考标准
- 良好:不超过 200 毫秒
- 需要改进:200~600 毫秒
- 较差:超过 600 毫秒
TBT 过高的常见原因
- JavaScript 包体积过大,解析和执行耗时过长
- 首屏同时初始化大量组件
- 复杂循环、数据处理或 JSON 解析占用主线程
- 第三方统计、广告或监控脚本执行时间过长
- 频繁触发样式计算、布局和渲染
常见优化方式
- 拆分长任务,让出主线程
- 使用代码分割,按需加载非首屏 JavaScript
- 删除无用代码,减少依赖和第三方脚本
- 将重计算放入 Web Worker
- 避免一次性渲染大量 DOM 节点
- 优化组件渲染和状态更新范围
五、INP:用户操作后多久看到反馈
INP(Interaction to Next Paint,交互到下一次绘制)衡量用户点击、触摸或键盘输入后,页面完成下一次视觉更新所需的时间。它是 Core Web Vitals 之一,用来评估页面整个访问期间的交互响应能力。
一次交互延迟通常包括三个部分:
- 输入延迟:事件发生后,主线程等待多久才开始处理
- 事件处理时间:事件回调本身执行了多久
- 呈现延迟:处理结束后,浏览器多久完成下一帧绘制
INP 会观察页面生命周期中的多次交互,并选取接近最差体验的结果,避免极少数异常值完全主导指标。因此,仅优化页面第一次点击是不够的,还需要关注弹窗打开、列表切换、搜索输入和表单提交等实际操作。
INP 的参考标准
- 良好:不超过 200 毫秒
- 需要改进:200~500 毫秒
- 较差:超过 500 毫秒
INP 过高的常见原因
- 交互发生时主线程正在执行长任务
- 事件回调中进行了大量同步计算
- 一次状态更新导致大范围组件重新渲染
- DOM 规模过大,布局和绘制成本高
- 输入事件触发过于频繁且没有合理控制
常见优化方式
- 缩短事件回调,把非必要工作延后执行
- 将大任务拆成多个小任务,及时让出主线程
- 减少一次交互引起的 DOM 更新范围
- 对超长列表使用虚拟滚动
- 避免布局抖动和强制同步布局
- 对适合的计算使用 Web Worker
TBT 和 INP 有什么区别
TBT 和 INP 都与主线程阻塞有关,但二者不能直接画等号:
| 指标 | 主要关注点 | 数据类型 | 是否需要真实交互 |
|---|---|---|---|
| TBT | 页面加载期间主线程被长任务阻塞的总时间 | 实验室指标 | 不需要 |
| INP | 用户交互发生后到下一次绘制的延迟 | 真实用户指标,也可本地调试 | 需要 |
Lighthouse 可以在受控环境中稳定测量 TBT,因此常用 TBT 辅助判断页面潜在的交互问题。但 TBT 良好不代表 INP 一定良好,因为用户可能在页面加载完成后遇到昂贵的交互逻辑;反过来,加载期间存在长任务,也不一定刚好阻塞了用户操作。
应该使用什么工具测量
- Lighthouse:适合自动审计 FCP、LCP、CLS 和 TBT,并给出优化建议
- Chrome DevTools Performance:适合录制加载和交互过程,定位 LCP 元素、布局偏移、长任务及具体函数耗时
- PageSpeed Insights:同时提供 Lighthouse 实验室数据和 Chrome 用户体验报告中的真实用户数据
- RUM 监控:适合持续采集线上真实用户的 LCP、CLS 和 INP
本地测试容易受到电脑性能、网络、缓存和浏览器扩展影响,建议在固定环境下多测几次。判断线上体验时,应以真实用户数据为主,并使用 Lighthouse 和 Performance 面板定位原因。
总结
可以用五句话记住这些指标:
- FCP:页面什么时候第一次出现内容
- LCP:首屏主要内容什么时候显示出来
- CLS:页面内容是否发生意外跳动
- TBT:加载期间主线程累计阻塞了多久
- INP:用户操作后多久看到下一次反馈
优化性能时,不应只追求单一分数。加载速度、视觉稳定性和交互响应共同决定了用户对页面“快不快”的真实感受。