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