精品軟體與實用教程
什麼是CLS?
CLS 測量整個頁面生命週期內發生的所有意外佈局偏移中最大一連串的佈局偏移分數。
每當一個可見元素的位置從一個已渲染幀變更到下一個已渲染幀時,就發生了佈局偏移 。
一連串的佈局偏移,也叫會話視窗,指一個或多個快速連續發生的單次佈局偏移,每次偏移相隔的時間少於1 秒,且整個視窗的最大持續時長為5 秒。
最大的一連串是指視窗內所有佈局偏移累積分數最大的會話視窗。
先前,CLS 測量的是整個頁面生命週期內發生的所有單次佈局偏移分數的總和。如需了解哪些工具仍以原方式提供測量功能,請查看網路工具集中不斷發展的累積佈局偏移 。
怎樣算是好的CLS 分數?
為了提供良好的使用者體驗,網站應該努力將CLS 分數控制在0.1 或以內。為了確保您能夠在大部分用戶的訪問期間達成建議目標值,一個良好的測量閾值為頁面加載的第75 個百分位數,且該閾值同時適用於行動和桌面設備
如需詳細了解這些建議值背後的研究和方法論,請參閱:定義核心Web 指標的指標閾值
佈局偏移詳情
佈局偏移由佈局不穩定性API定義,只要可視區域中可見元素的起始位置(例如,元素在預設書寫模式下方的頂部和左側位置)在兩個畫面之間發生了變更,該API 就會報告 layout-shift 條目。這樣的元素被視為不穩定元素。
請注意,只有當現有元素的起始位置發生變更時才算作佈局偏移。如果將新元素新增至DOM 或是現有元素變更大小,則不算作佈局偏移,前提是元素的變更不會導致其他可見元素的起始位置變更。
佈局偏移分數
瀏覽器在計算佈局偏移分數時,會查看可視區域大小和兩個已渲染幀之間的可視區域中不穩定元素的位移。佈局偏移分數是該位移的兩個測量值的乘積:影響分數和距離分數(兩者定義如下)。
版面偏移分數= 影響分數* 距離分數
影響分數
影響分數測量不穩定元素對兩幀之間的可視區域產生的影響。
前一幀和目前幀的所有不穩定元素的可見區域集合(佔總可視區域的部分)就是目前影格的影響分數。
在上圖中,有一個元素在一幀中佔據了一半的可視區域。接著,在下一幀中,元素下移了可視區域高度的25%。紅色虛線矩形框表示兩個畫面中元素的可見區域集合,在本範例中,該集合佔總可視區域的75%,因此其影響分數為0.75 。
距離分數
佈局偏移分數計算公式的另一部分測量不穩定元素相對於可視區域位移的距離。距離分數指的是任何不穩定元素在一幀中位移的最大距離(水平或垂直)除以可視區域的最大尺寸維度(寬度或高度,以較大者為準)。
在上方的範例中,最大的可視區域尺寸維度是高度,不穩定元素的位移距離為可視區域高度的25%,因此距離分數為0.25。
所以,在這個範例中,影響分數是0.75 ,距離分數是0.25 ,所以佈局偏移分數是0.75 * 0.25 = 0.1875 。
最初,佈局偏移分數只根據影響分數進行計算。引入距離分數是為了避免在大元素發生微小位移的情況下進行過度懲罰的情況。
下一個範例說明了向現有元素添加內容對佈局偏移分數的影響:
"點我!"按鈕附加在了包含黑色字體文字的灰色框底部,將帶有白色字體文字的綠色框下推(且一部分已在可視區域外)。
在這個範例中,灰色框的大小改變了,但起始位置沒有改變,所以該灰色框不是一個不穩定元素。
"點我!"按鈕一開始並不在DOM 中,所以它的起始位置也沒有改變。
然而,綠色框的起始位置確實發生了變化,但由於綠色框的一部分已經在可視區域外,因此在計算影響分數時不考慮不可見區域。兩幀中綠色框的可見區域集合(以紅色虛線矩形框表示)與第一幀中綠色框的區域相同,為可視區域的50%。影響分數為0.5 。
距離分數由紫色箭頭表示。綠色框向下移動的距離大約是可視區域的14%,因此距離分數為0.14 。
佈局偏移分數是0.5 x 0.14 = 0.07 。
最後一個範例說明了多個不穩定元素的情況:
在上面的第一幀中,有四個API 請求的動物名稱結果,按首字母順序進行了排序。在第二幀中,更多的結果被添加到排序列表中。
清單中第一項("Cat")的起始位置沒有在兩個畫面之間改變,因此是穩定的。同樣,在新增到清單中的新項目之前不在DOM 中,因此這些項目的起始位置也沒有改變。但"Dog"、"Horse"和"Zebra"這幾項的起始位置都發生了改變,因此都是不穩定元素。
同理,紅色虛線矩形框代表這三個不穩定元素前後兩幀的區域集合,在本例中,大約佔可視區域面積的38%(影響分數為0.38 )。
箭頭表示不穩定元素相對於起始位置的位移距離。由藍色箭頭表示的"Zebra"元素位移的距離最大,約為可視區域高度的30%。因此本範例中的距離分數為0.3 。
佈局偏移分數是0.38 x 0.3 = 0.1172 。
預期佈局偏移vs. 意外佈局偏移
佈局偏移並不總是壞事。事實上,許多動態網頁應用程式經常會更改頁面元素的起始位置。
由使用者發起的佈局偏移
佈局偏移只有在使用者不期望其發生時才算是壞事。換言之,對用戶互動(點擊連結、點選按鈕、在搜尋框中鍵入資訊等)進行回應的佈局偏移通常沒有問題,前提是偏移發生的時機與互動時機足夠接近,使用戶對前後關係一目了然。
例如,如果某次使用者互動觸發了一個網路請求,而該請求可能需要一段時間才能完成,那麼最好立即留出一些空間並顯示載入指示器,避免在請求完成時出現令使用者不快的佈局偏移。如果用戶沒有意識到目前正在加載某些內容,或者不知道資源什麼時候能夠準備就緒,他們就可能會在等待期間嘗試點擊其他內容(來打破僵局)。
在使用者輸入500 毫秒內發生的佈局偏移會帶有hadRecentInput標誌,便於在計算中排除這些偏移。
注意:hadRecentInput標誌僅適用於不連續輸入事件,例如輕觸、點擊或按鍵操作。滾動、拖曳或捏拉縮放手勢等連續性互動操作不算作"最近輸入"。更多詳情請參閱佈局不穩定性規範。
動畫和過渡
動畫和過渡如果做得好,確實是一個在更新頁面內容時不讓用戶感到突兀的好方法。頁面內容突然發生意外偏移幾乎無一例外會造成糟糕的使用者體驗。但如果內容從一個位置逐步又自然地移動到下一個位置,這通常有助於使用者更好地明白當前狀況,並引導他們適應狀態之間的變化。
CSS transform屬性使您能夠在不觸發佈局偏移的情況下為元素設定動畫:
- 用transform: scale()來取代和調整height和width屬性。
- 如需讓元素能夠四處移動,可以用transform: translate()來取代和調整top、right、bottom或left屬性。
如何測量CLS
CLS 可以進行實驗室測量或實際測量,並且可以在以下工具中使用:
注意:實驗室工具通常在一個合成環境中載入頁面,因此只能測量頁面載入期間發生的佈局偏移。因此,實驗室工具為某一特定頁面所報告的CLS 值可能低於真實使用者的實際體驗值。
實測工具
實驗室工具
在JavaScript 中測量CLS
要在JavaScript 中測量CLS,您可以使用佈局不穩定性API。以下範例說明如何建立一個PerformanceObserver來偵聽意外layout-shift條目、將條目按會話分組、記錄最大會話值,並在最大會話值發生改變時更新記錄。
let clsValue = 0;
let clsEntries = [];
let sessionValue = 0;
let sessionEntries = [];
new PerformanceObserver((entryList) => {
for (const entry of entryList.getEntries()) {
// 只將不帶有最近使用者輸入標誌的佈局偏移計算在內。
if (!entry.hadRecentInput) {
const firstSessionEntry = sessionEntries[0];
const lastSessionEntry = sessionEntries[sessionEntries.length - 1];
// 若條目與上一條目的相隔時間小於1 秒且
// 與會話中第一個條目的相隔時間小於5 秒,那麼將條目
// 包含在目前會話中。否則,開始一個新會話。
if (sessionValue &&
entry.startTime - lastSessionEntry.startTime < 1000 &&
entry.startTime - firstSessionEntry.startTime < 5000) {
sessionValue += entry.value;
sessionEntries.push(entry);
} else {
sessionValue = entry.value;
sessionEntries = [entry];
}
// 如果目前會話值大於目前CLS 值,
// 那麼更新CLS 及其相關條目。
if (sessionValue > clsValue) {
clsValue = sessionValue;
clsEntries = sessionEntries;
// 將更新值(及其條目)記錄在控制台中。
console.log('CLS:', clsValue, clsEntries)
}
}
}
}).observe({type: 'layout-shift', buffered: true});
警告:上述程式碼說明了計算和記錄CLS 的基本方法。但是,要準確測量CLS,使其與Chrome 使用者體驗報告 (CrUX) 中的測量值相匹配,那麼測量方式要更為複雜。詳情請見下文:
在大多數情況下,頁面卸載時的目前CLS 值就是該頁面的最終CLS 值,但有一些重要的例外:
以下部分列出了API 報告的內容與指標計算方式的差異。
指標和API 之間的差異
- 如果頁面是在背景載入的,或者頁面在瀏覽器繪製任何內容之前被轉移到後台,那麼該頁面不應該報告任何CLS 值。
- 如果頁面透過往返緩存恢復,則該頁面的CLS 值應重設為零,因為這對使用者來說是多次不同的頁面存取體驗。
- API 不會基於iframe 中的偏移量來報告layout-shift條目,但若要正確測量CLS,您應該考慮這些偏移。子框架可以使用API 將這些偏移的layout-shift條目報告給父框架來進行聚合。
由於CLS 的測量對像是整個頁面生命週期,所以除了上述這些例外,該指標還有一些額外的複雜性:
- 用戶可能會在很長一段時間內(幾天、幾週、幾個月)讓一個選項卡保持開啟。事實上,用戶可能永遠不會關閉該選項卡。
- 在行動作業系統上,瀏覽器通常不會為後台選項卡執行頁面卸載回調,因為這樣很難報告"最終"值。
為了應對這些情況,只要當頁面處於背景時就應該報告CLS,頁面卸載時也是如此(visibilitychange事件涵蓋這兩種情況)。而接收該資料的分析系統則需要在後端計算最終的CLS 值。
開發者不必記住所有這些情況並獨自應付,而是可以使用web-vitals JavaScript 函式庫來測量CLS,庫會自行處理上述所有情況:
import {getCLS} from 'web-vitals';
// 在所有需要回報CLS 的情況下
// 對其進行測量和記錄。
getCLS(console.log);
您可以參考(getCLS)的原始程式碼,以了解如何在JavaScript 中測量CLS 的完整範例。
在某些情況下(例如跨域iframe),LCP 無法在JavaScript 中進行測量。詳情請參閱web-vitals庫的限制部分。
如何改進CLS
對於大多數網站來說,您可以透過遵循一些指導原則來避免所有的意外佈局偏移:
- 始終在您的圖像和視訊元素上包含尺寸屬性,或透過使用CSS 長寬比容器之類的方式預留所需的空間。這種方法可以確保瀏覽器能夠在載入映像期間在文件中分配正確的空間大小。請注意,您也可以使用unsized-media 功能策略在支援功能策略的瀏覽器中強制執行此行為。
- 除非是對使用者互動做出回應,否則切勿在現有內容的上方插入內容。這樣能夠確保發生的任何佈局偏移都在預期之內。
- 首選轉換動畫,而不是觸發佈局偏移的屬性動畫。動畫過渡的目標是提供狀態與狀態之間的上下文連續性。