跳转到内容

性能 · 概念

Core Web Vitals(LCP、INP 与 CLS)

发布于 更新于

Core Web Vitals 是三项现场指标,Google 的工具把它们当作「良好页面体验」的定义:衡量加载的 Largest Contentful Paint、衡量响应性的 Interaction to Next Paint,以及衡量视觉稳定性的 Cumulative Layout Shift。真实访问的第 75 百分位在三项上都达到「良好」即为通过,而 PWA 的 Service Worker、任务调度和布局预留正是能推动每一项的手段。

每个指标都是通过 PerformanceObserver 暴露的 PerformanceEntry 类型,在一次访问内汇总,再由 web-vitals 库或 Chrome User Experience Report(CrUX)从现场上报。阈值来自 Chrome 团队对用户感知质量的校准(Web Vitals,web.dev)。

指标 测量内容 良好 待改进 差 条目类型
LCP 视口内最大图片或文本块相对导航开始的渲染时间 ≤ 2.5 s ≤ 4.0 s > 4.0 s largest-contentful-paint(Chrome 77、Firefox 122、Safari 26.2)
INP 整次访问中最慢交互从输入到下一次绘制的延迟,交互很多的页面按高百分位截断 ≤ 200 ms ≤ 500 ms > 500 ms 带 interactionId 的 event(Chrome 96、Firefox 144、Safari 26.2)
CLS 最差会话窗口内意外布局偏移得分之和 ≤ 0.1 ≤ 0.25 > 0.25 layout-shift(仅 Chromium)

INP 于 2024 年 3 月取代 First Input Delay 成为响应性指标(Interaction to Next Paint,web.dev);FID 只测首次交互的输入延迟,INP 则包含处理时间和其后那一帧的绘制。阈值按页面访问的第 75 百分位计算,移动端与桌面端分开。

INP 与 CLS 在整次访问中累积,所以 Lighthouse 或 WebPageTest 的单次脚本加载无法复现它们;实验室工具用 Total Blocking Time 和加载期 CLS 作为替代。CrUX 为流量足够的源发布现场分布,web-vitals 库通过 onLCP()、onINP()、onCLS() 回调给出页面自己的数字。用实验室找原因,用现场下结论。

在现场测量取决于引擎是否暴露对应条目:largest-contentful-paint 在 Chrome 77、Firefox 122、Safari 26.2;带 interactionId 的 event 条目在 Chrome 96、Firefox 144、Safari 26.2;layout-shift 仅 Chromium(BCD api.LargestContentfulPaint、api.PerformanceEventTiming.interactionId、api.LayoutShift)。CrUX 以及搜索工具据此报告的现场数字只从 Chrome 采集。

  • LCP。 Service Worker 中的缓存优先或 stale-while-revalidate 策略让重复访问从 Cache Storage 取得外壳和主图,把网络从关键路径上拿掉;见预缓存。首次访问的手段是 LCP 图片上的 fetchpriority="high"、首屏不做懒加载,以及把图片 URL 放进 HTML 而不是脚本里的服务端响应。
  • INP。 主线程上的长任务推迟下一次绘制。用 scheduler.yield() 或 setTimeout 分块拆开工作,把解析和 hydration 移出交互路径,让事件处理函数保持短小;缩减启动时执行的代码量见代码拆分。
  • CLS。 在内容到达前预留空间:图片和嵌入内容的 width、height 或 aspect-ratio、延迟出现的横幅的固定高度槽位,以及 font-display: optional 或度量匹配的后备字体,使 Web 字体替换不会让文本重排;见字体与图片优化。

三种条目类型不借助任何库就能在 Chrome 中看到。下面的代码在浏览器报告每个指标时打印它,并在引擎缺少该条目类型时降级为「不支持」,Chromium 之外的 layout-shift 就是这种情况。

function observe(type, handler) {
if (!('PerformanceObserver' in window)
|| !PerformanceObserver.supportedEntryTypes.includes(type)) {
return false; // 这里不支持该条目类型:这项指标不上报
}
new PerformanceObserver((list) => list.getEntries().forEach(handler)).observe({ type, buffered: true });
return true;
}
observe('largest-contentful-paint', (e) => console.log('LCP 候选', e.startTime, e.element));
observe('layout-shift', (e) => { if (!e.hadRecentInput) console.log('偏移', e.value, e.sources); });
observe('event', (e) => { if (e.interactionId) console.log('交互', e.name, e.duration); });

largest-contentful-paint 会随着更大的候选元素渲染而多次触发;首次交互或切换标签页之前的最后一条就是 LCP。layout-shift 条目带 hadRecentInput,用于排除用户输入后 500 ms 内的偏移,sources 则列出发生偏移的节点。

规范

规范状态
无。