本文是译文,关注Web Vitals Metrics,翻译系列文章中的03篇
原文连接: Cumulative Layout Shift (CLS)
浏览网页时你是否遇到过页面上的内容忽然改变的状况?没有任何征兆地文本移动了位置,致使你都不知道读到哪了。或者更有甚者:当你要点击按钮、连接的时候,忽然连接位置变了,让你点击到了别的连接上!发生这种状况让人体验很是很差,在另外的场景下会形成灾难性后果。javascript
由于网站中的资源是异步下载的,页面内容也能够动态地添加到已有内容上,因此内容发生非预期变化的场景比较常见。未设置宽高的<image>
、<video>
元素,实际使用的字体与备用大小不一致,能够动态变动大小的第三方广告或者组件都有多是致使页面发生非预期偏移的“罪魁祸首”。java
站点在开发环境的表现与实际用户感觉到的有很大差别。开发、生产环境中个性化、第三方内容一般表现也有不一致的状况,好比:测试图片缓存在开发者浏览器缓存之中;本地的API运行得很快,其延迟都没法观测到。CLS经过帮助咱们衡量用户实际访问页面时布局偏移发生的几率,来解决开发、生产环境中页面表现不一致的问题。web
衡量的是页面整个生命周期中每次元素发生的非预期布局偏移得分的总和。每次可视元素在两次渲染帧中的起始位置不一样时,就说是发生了LS(Layout Shift)。算法
CLS<0.1,一样标准须要覆盖站点75%的用户浏览器
LS的由Layout Instability API定义,每当视口中两次渲染帧之间的可视元素改变了其起始位置时都会触发layout-shift entries,改变了起始位置的元素被认为是不稳定元素。因为LS只会发生在改变了初始位置的已有元素上,只要新加入的元素并不会形成其余可见元素改变位置,它将不会被当成是LS元素。缓存
为了计算出LS分数,浏览器关注视口大小和视口中两个渲染帧之间不稳定元素的移动状况。LS得分等于 影响小数与 距离小数的乘积。咱们分别来看看这两个因数是如何算出来的。网络
layout shift score = impact fraction × distance fraction
衡量的是不稳定元素渲染帧先后对视口的影响大小
不稳定元素在以前渲染帧中的可视区域 和 当前帧可视区域的并集,即为影响小数。举个例子:在图1中展现的页面渲染帧中,元素占据了一半的视口。以后,在下一个渲染帧,元素往下偏移了视口高度的25%。红色虚线表示的即为两帧不稳定元素可视区域的并集。在这里例子里,占据了视口大小的75%,所以影响小数值为0.75。异步
衡量的是不稳定元素相对于视口移动的距离。
距离小数等于不稳定元素在渲染帧中移动的最大距离(水平或者垂直方向上)除以视口宽或者高(谁大取谁)。在上述例子中,移动距离是垂直方向上,移动了25%视口高,如图1中蓝色箭头,所以距离小数为0.25。所以,在图1给定的例子里面,LS得分为0.75*0.25 = 0.1875。如图1:ide
接下来的例子演示给已有元素新增内容是如何影响LS得分的。如图2:
Click me按钮挂载在含有黑色文本的灰色盒子里,它将含有白色文本的绿色盒子往下推(部分被推出视口)。图2例子中,灰色盒子虽然改变了大小,但其起始位置没有变化,因此他不是一个不稳定元素。按钮以前不存在,它的起始位置没变,也不是不稳定元素。绿色盒子的起始位置发生了变化,它是一个不稳定元素。另外,因为它部分被推出了视口以外,不可见部分不会参与计算影响小数。绿色盒子在2个渲染帧中出现的可视部分的并集占据了视口的50%。所以影响小数为0.5。图中的紫色箭头说明的是距离小数,绿色盒子大概移动了视口的14%,所以距离小数值为:0.14。合计LS得分为0.5*0.14=0.07。工具
最后这个例子演示了视口中出现多个不稳定元素的状况。如图3:
第一帧展现的是请求API后4种动物数据,以字母顺序排列。第二帧图加了更多元素。Cat所在的元素起始位置没变,它是稳定的。相似的,新加的元素起始位置也没有变化。标记为Dog、Horse和Zebra的元素都偏移了他们的起始位置,它们都是不稳定元素。红色虚线框表明的是这3个不稳定元素偏移先后占据视口的并集,大概占据了视口区域的38%(影响小数为0.38)。箭头表示着不稳定元素偏离其初始位置的距离。蓝色箭头的Zebra元素,相对视口高度约改变了30%(所以距离小数为:0.3)。 最终Zebra元素的LS得分为:0.38*0.3。
也不是全部的LS都是个问题,非预期的LS才是。像基于用户操做响应致使的LS是能够接受的,只要偏移发生的时机跟响应用户的操做之间联系足够紧密。举个例子:用户发起的网络请求须要等待必定时间才能完成,最好当即建立布局空间,展现loading正在加载的指示组件来避免请求完成后发生LS。若是用户看不到加载正在进行,或者请求完成以后无从得知,用户在等待期间就会去点击别的地方。发生在用户输入以后500ms之内的LS将会被打上标记,不会参与LS计算。
动画、渐变若是使用得当的话是一个较好的更新页面内容的办法,不会让用户以为突兀。页面上内容粗暴的、意外的偏移会带来糟糕的用户体验。内容若是渐进、天然地从一处移动到另一处有助于用户理解页面上发生的事,也能为用户提供指引。
CSS的transform属性能够作到不引起LS的状况下实现动画效果:
a. 用transform:scale()替代height、width属性的变化;
b. 用translate()替代top、right、bottom、left属性的变化。
Chrome User Experience Report
PageSpeed Insights
Search Console (Core Web Vitals report)
web-vitals JavaScript library
Chrome DevTools
Lighthouse
WebPageTest
Layout Instability API + PerformanceObserver
let cls = 0; new PerformanceObserver((entryList) => { for (const entry of entryList.getEntries()) { if (!entry.hadRecentInput) { cls += entry.value; console.log('Current CLS value:', cls, entry); } } }).observe({type: 'layout-shift', buffered: true});
说明:全部具备hadRecentInput标记的layout-shift entries累加值即为CLS值,大部分时候,最终的CLS会在页面unload,但也存在以下例外状况:页面在后台的不参与、缓存中的和iframe中页面也不参与。除了例外状况,因为CLS贯穿整个页面的生命周期的特性也增长了其计算的复杂性。好比用户打开tab页面好久都不关掉、移动端浏览器不会为后台运行的tab执行页面unload回调。一样,细节较多,咱们建议使用开发好的工具库来测量CLS。
import {getCLS} from 'web-vitals'; getCLS(console.log);
严格遵循如下原则,就能够避免站点中大部分非预期CLS问题,内容有:
(1)给image
、vide
元素设置size属性,或者预留以后须要的布局空间。这个作法确保让浏览器在图片正在加载时就分配好正确的文档空间。
(2)除非为了响应用户,不要在已有内容上插入内容
(3)把触发布局改变的属性改用transform动画的方式
更多关于优化CLS的方法,请参考:优化CLS章节(待补充)
其它参考:
1.减小layout-shift
2.理解CLS