瞭解如何找出及修正版面配置位移。
本文第一部分探討用於對版面配置位移偵錯的工具,第二部分則討論用於找出版面配置位移原因時的思考流程。
工具
版面配置不穩定 API
Layout Instability API 是測量和回報版面配置位移的瀏覽器機制。所有用於對版面配置位移偵錯的工具 (包括開發人員工具) 最終都是以 Layout Instability API 建構而成。不過,由於靈活彈性,直接使用 Layout Instability API 是功能強大的偵錯工具。
使用方式
用來評估累計版面配置位移 (CLS) 的同一個程式碼片段,也可用於對版面配置位移進行偵錯。下方的程式碼片段會記錄版面配置轉移至控制台的相關資訊。檢查此記錄即可瞭解版面配置位移發生的時間、位置和方式。
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});
執行這個指令碼時,請注意下列事項:
buffered: true
選項代表PerformanceObserver
應檢查瀏覽器的效能項目緩衝區,找出在觀察器初始化前建立的效能項目。因此,PerformanceObserver
會回報在初始化前後發生的版面配置位移。檢查主控台記錄檔時,請注意這一點。版面配置位移的初始模糊處理可以反映報表待處理作業,而非因多次版面配置位移突然發生。- 為了避免影響效能,
PerformanceObserver
會等到主要執行緒處於閒置狀態時,回報版面配置位移。因此,視主要執行緒的忙碌程度而定,版面配置的位移與在主控台中記錄時,可能會有短暫的延遲。 - 這個指令碼會忽略使用者輸入內容在 500 毫秒內發生的版面配置位移,因此不會計入 CLS。
系統會結合使用 LayoutShift
和 LayoutShiftAttribution
介面,回報版面配置位移的相關資訊。以下各節將詳細說明這些介面。
LayoutShift
每個版面配置位移都會透過 LayoutShift
介面回報。項目的內容如下所示:
duration: 0
entryType: "layout-shift"
hadRecentInput: false
lastInputTime: 0
name: ""
sources: (3) [LayoutShiftAttribution, LayoutShiftAttribution, LayoutShiftAttribution]
startTime: 11317.934999999125
value: 0.17508567530168798
上方項目表示版面配置的位移,導致三個 DOM 元素改變位置。這個特定版面配置位移的版面配置位移分數為 0.175
。
下列為與版面配置位移偵錯作業最相關的 LayoutShift
例項屬性:
屬性 | 說明 |
---|---|
sources |
sources 屬性會列出版面配置位移期間移動的 DOM 元素。這個陣列最多可包含五個來源。如果在版面配置位移影響超過五個元素,系統會回報版面配置位移的五大 (評估依據對版面配置穩定性的影響) 來源。這項資訊是透過 LayoutShiftAttribution 介面回報 (詳情請參閱下方說明)。 |
value |
value 屬性會回報特定版面配置位移的版面配置位移分數。 |
hadRecentInput |
hadRecentInput 屬性可指出版面配置的位移是否在使用者輸入內容的 500 毫秒內發生。 |
startTime |
startTime 屬性會指出版面配置位移的時間。startTime 表示單位為毫秒,且會根據網頁載入啟動時間進行測量。 |
duration |
duration 屬性一律設為 0 。這個屬性是繼承自 PerformanceEntry 介面 (LayoutShift 介面會擴充 PerformanceEntry 介面)。不過,時間長度的概念不適用於版面配置位移事件,因此設為 0 。如要瞭解 PerformanceEntry 介面,請參閱spec。 |
LayoutShiftAttribution
LayoutShiftAttribution
介面說明單一 DOM 元素的一次移動。如果多個元素在版面配置位移期間移動,sources
屬性會包含多個項目。
舉例來說,下列 JSON 對應了含有一個來源的版面配置位移:<div id='banner'>
DOM 元素的從 y: 76
向下移動至 y:246
。
// ...
"sources": [
{
"node": "div#banner",
"previousRect": {
"x": 311,
"y": 76,
"width": 4,
"height": 18,
"top": 76,
"right": 315,
"bottom": 94,
"left": 311
},
"currentRect": {
"x": 311,
"y": 246,
"width": 4,
"height": 18,
"top": 246,
"right": 315,
"bottom": 264,
"left": 311
}
}
]
node
屬性會識別已移動的 HTML 元素。在開發人員工具中將滑鼠遊標懸停在這項屬性上,即可醒目顯示對應的頁面元素。
previousRect
和 currentRect
屬性會回報節點的大小和位置。
x
和y
座標會分別回報元素左上角的 x 座標和 y 座標。width
和height
屬性會分別回報元素的寬度和高度。top
、right
、bottom
和left
屬性會回報與元素指定邊緣相對應的 x 或 y 座標值。換句話說,top
的值等於y
;bottom
的值等於y+height
。
如果 previousRect
的所有屬性都設為 0,表示元素已移至檢視畫面。如果 currentRect
的所有屬性都設為 0,表示元素已從檢視畫面中移出。
解讀這些輸出內容時,最需要瞭解的一點是,列為「來源」的元素是在版面配置位移期間轉移的元素。不過,這些元素可能會與版面配置不穩定的「根本原因」間接相關。以下列舉幾個例子。
示例 1
系統會回報這個版面配置位移,內含一個來源:元素 B。不過,這種版面配置位移的根本原因是元素 A 的大小變更。
示例 2
這個範例中的版面配置位移會回報兩個來源:元素 A 和元素 B。這種版面配置位移的根本原因是元素 A 的位置變更。
示例 3
在本例中,版面配置位移會回報一個來源:元素 B。變更元素 B 的位置會導致版面配置位移。
示例 4
雖然元素 B 會變更大小,但在本範例中並沒有版面配置位移。
請參閱這個示範影片,瞭解 Layout Instability API 如何回報 DOM 變更情形。
DevTools
效能面板
開發人員工具的「Performance」面板的「Experience」窗格會顯示特定效能追蹤記錄期間的所有版面配置位移,即使版面配置是在使用者互動後 500 毫秒內發生,也不會計入 CLS。將滑鼠遊標懸停在「Experience」面板中的特定版面配置位移,會醒目顯示受影響的 DOM 元素。
如要進一步瞭解版面配置位移,請按一下版面配置位移,然後開啟「Summary」導覽匣。系統會使用 [width, height]
格式列出元素尺寸的變更,請使用 [x,y]
格式列出元素位置的變更。「HadRecent input」屬性可指出版面配置的位移是否在使用者互動後 500 毫秒內發生。
如要瞭解版面配置位移的持續時間,請開啟「Event Log」(事件記錄) 分頁標籤。您也可以透過在「Experience」窗格中查看紅色版面配置位移矩形的長度,大致瞭解版面配置位移的持續時間。
如要進一步瞭解如何使用「Performance」面板,請參閱「效能分析參考資料」。
醒目顯示版面配置位移區域
強調版面配置位移區域是一項實用技巧,可讓您快速且快速地掌握網頁上的版面配置位移位置和時間。
如要在開發人員工具中啟用版面配置位移區域,請依序前往「Settings」>「More Tools」>「Rendering」>「Layout Shift Regions」,然後重新整理要偵錯的網頁。版面配置位移的區域會以紫色快速醒目顯示。
找出版面配置位移原因的思維程序
無論版面配置位移的時間或方式為何,您都可以按照下列步驟找出版面配置位移的原因。這些步驟可以利用執行 Lighthouse 來補充,但請注意,Lighthouse 只能識別初始頁面載入期間發生的版面配置位移。此外,Lighthouse 也可以只針對版面配置位移的某些原因 (例如沒有明確寬度和高度的圖片元素) 提供建議。
找出版面配置位移的原因
下列事件可能會導致版面配置位移:
- DOM 元素位置變更
- DOM 元素的維度變更
- 插入或移除 DOM 元素
- 觸發版面配置的動畫
特別是,移動的元素前的 DOM 元素是最有可能涉及「造成」版面配置位移的元素。因此,在調查版面配置位移發生的原因時,請考慮以下幾點:
- 上述元素的位置或尺寸是否改變?
- 經過移動的元素之前,是否已插入或移除 DOM 元素?
- 已移動元素的位置是否明確變更?
如果上述元素沒有造成版面配置位移,請考慮其他前後元素來繼續搜尋。
此外,版面配置位移的方向和距離也能提供根本原因的提示。舉例來說,較大的向下移通常代表插入 DOM 元素,而 1 px 或 2 像素的版面配置位移通常表示套用了衝突的 CSS 樣式,或載入與套用網站字型的應用程式。
以下是最常導致版面配置位移事件的一些特定行為:
變更元素的位置 (非因移動其他元素而造成)
這類變更通常源自於:
- 延遲載入或覆寫先前宣告的樣式。
- 動畫和轉場效果。
元素尺寸變更
這類變更通常源自於:
- 延遲載入或覆寫先前宣告的樣式。
- 不含
width
和height
屬性的圖片和 iframe,會在「版位」轉譯後載入。 - 不含
width
或height
屬性的文字區塊,會在轉譯文字後交換字型。
插入或移除 DOM 元素
原因通常是:
- 插入廣告和其他第三方嵌入內容。
- 插入橫幅、快訊和視窗。
- 會在現有內容上方載入額外內容的無限捲動和其他使用者體驗模式。
觸發版面配置的動畫
部分動畫效果可以觸發版面配置。常見的例子是, DOM 元素是透過遞增 top
或 left
等屬性的方式「動畫」,而不是使用 CSS 的 transform
屬性。詳情請參閱「如何建立高效能的 CSS 動畫」一文。
重現版面配置位移
您無法修正無法重現的版面配置位移。如要深入瞭解網站版面配置的穩定性,最簡單有效的方法之一是需要 5 至 10 分鐘與網站互動,目標是觸發版面配置位移。執行這項作業時,請將主控台保持開啟,並使用 Layout Instability API 回報版面配置位移。
為難以找出版面配置位移,建議您使用不同裝置和連線速度重複這項練習。具體來說,連線速度越慢,越容易找出版面配置位移。此外,您也可以使用 debugger
陳述式,更輕鬆逐步完成版面配置位移。
new PerformanceObserver((entryList) => {
for (const entry of entryList.getEntries()) {
if (!entry.hadRecentInput) {
cls += entry.value;
debugger;
console.log('Current CLS value:', cls, entry);
}
}
}).observe({type: 'layout-shift', buffered: true});
最後,如果版面配置的問題無法在開發過程中重現,請考慮將 Layout Instability API 與選用的前端記錄工具搭配使用,以便收集這些問題的更多資訊。請參閱如何追蹤網頁上最大位移元素的程式碼範例。