Core Web Vitals

Google总结了健康网络的三个指标,旨在提高用户体验:

  • Largest Contentful Paint (LCP): 最大内容绘制
  • First Input Delay (FID): 首次输入延迟
  • Cumulative Layout Shift (CLS): 累积布局转移
    指标其实分别对应网站健康度的三个方面:加载、交互性、页面稳定性。
    本文对这篇文章做总结,包含三个部分:指标定义,如何度量,如何优化。

LCP

是衡量页面加载性能的核心指标,表示视口中最大的文字或者图片块渲染的时间。

largest contentful elements 有以下几类:

  • img 标签
  • SVG 中的 image
  • 设置封面的 video
  • 通过 background:url()加载背景的元素
  • 包含了文本节点的块级元素

需要注意的是,增加元素,删除元素会可能会改变 largest contentful element。
并且,加载没有完成的图片,字体没有加载完成的文字,也不能被认为是 contentful element,只有当加载完成后才是。
如果用户与页面有交互事件的发生(点击,滑动),浏览器就不会发布新的largest- contentful-paint 事件

测量

使用 PerformanceObserver API测量

new PerformanceObserver((entryList) => {})
.observe({type: ‘largest-contentful-paint’});
一般来说最后一个entry的startTime就是 largest-contentful-paint 时间,但也有例外的情况,主要是和background tab 相关。

Google已经提供了测量工具:https://github.com/GoogleChrome/web-vitals

也存在最大的元素并不是最重要的情况,这时候就需要自定义Timing工具 https://wicg.github.io/element-timing/

优化

导致LCP很糟糕的原因主要有以下几种:

  • 服务器响应慢(没错,甩锅给后端是每个前端必备的能力)
  • JS 或者 CSS 阻塞
  • 资源加载慢
  • 客户端渲染慢

对与服务器响应慢的情况,首先使用 window.performance.timing 来测量 TTFB,看是否因为服务器的问题。然后就是服务器优化的问题了,不展开。CDN,Cache等。

新增知识点get: 通过 <link rel="preconnect" href="https://example.com" /> 可以提前与服务器建立连接。或者 dns-prefetch 提前获得IP地址(不过这个因为缓存的原因,只有第一次请求的时候会有提高)

对于CSS阻塞渲染的情况,除了常见的减小体积,内联重要的css,还有一个是异步,用一个link标签就可以搞定:
<link rel="stylesheet" href="/path/to/my.css" media="print" onload="this.media='all'; this.onload=null;">

在页面初始化的时候,仅加载需要用到的CSS样式,再异步请求剩余的CSS内容是比较好的处理方法,而且有已经有webpack插件来处理 https://github.com/GoogleChromeLabs/critters

FID

用户第一次与页面交互到执行监听事件所需的时间。

当主线程繁忙(解析或者执行JS文件的时候),浏览器不会立即响应用户操作。

测量:

因为FID的测量需要用户点击,所以在实验环境中使用Total Blocking Time(TBT)

优化:

  • 超过50ms的任务被认为是长任务。分割长任务为多个小的,异步执行任务是有效的方式。
  • 使用 webworker

CLS

元素改变位置的得分总和

分数是影响分数和距离分数的乘积

layout shift score = impact fraction * distance fraction
impact fraction 代表前后两帧中,不稳定元素占视口的比例

distance fraction 代表所有不稳定元素中移动距离占视口的最大比例

优化:

  • 图片和视频需要加上尺寸属性
  • 除非用户交互,否则不要在已有的元素上插入新的元素
  • 使用 transform 动画

参考文档:

https://web.dev/learn-web-vitals/
https://web.dev/optimize-lcp/
https://wicg.github.io/element-timing/
https://github.com/filamentgroup/loadCSS/blob/master/README.md