本文是譯文,關注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