修正版面配置不穩定性

逐步說明如何使用 WebPageTest 找出並修正版面配置不穩定問題。

我在先前的文章中,介紹了如何使用 WebPageTest 評估累計版面配置位移 (CLS)。CLS 是所有版面配置位移的匯總,因此在本文中,我想深入探討並檢查網頁上的每個版面配置位移,試著瞭解可能導致不穩定的原因,並實際修正問題。

測量版面配置位移

使用 Layout Instability API,我們可以取得網頁上所有版面配置位移事件的清單:

new Promise(resolve => {
  new PerformanceObserver(list => {
    resolve(list.getEntries().filter(entry => !entry.hadRecentInput));
  }).observe({type: "layout-shift", buffered: true});
}).then(console.log);

這會產生未在輸入事件前發生的版面配置位移陣列:

[
  {
    "name": "",
    "entryType": "layout-shift",
    "startTime": 210.78500000294298,
    "duration": 0,
    "value": 0.0001045969445437389,
    "hadRecentInput": false,
    "lastInputTime": 0
  }
]

在本例中,210 毫秒時只有 0.01% 的極小幅度變化。

瞭解變動的時間和嚴重程度,有助於縮小變動原因的範圍。讓我們回到 WebPageTest 實驗室環境,進行更多測試。

在 WebPageTest 中測量版面配置位移

與在 WebPageTest 中評估 CLS 類似,評估個別版面配置位移需要使用自訂指標。幸好,Chrome 77 穩定版推出後,這個程序變得簡單許多。版面配置不穩定性 API 預設為啟用,因此您應該可以在 Chrome 77 中的任何網站上執行該 JS 片段,並立即取得結果。在 WebPageTest 中,您可以使用預設的 Chrome 瀏覽器,不必擔心指令列標記或使用 Canary。

因此,請修改該指令碼,為 WebPageTest 產生自訂指標:

[LayoutShifts]
return new Promise(resolve => {
  new PerformanceObserver(list => {
    resolve(JSON.stringify(list.getEntries().filter(entry => !entry.hadRecentInput)));
  }).observe({type: "layout-shift", buffered: true});
});

這個指令碼中的 Promise 會解析為陣列的 JSON 表示法,而非陣列本身。這是因為自訂指標只能產生字串或數字等基本資料型別。

我將使用 ismyhostfastyet.com 進行測試,這個網站是我用來比較網頁主機實際載入效能的工具。

找出版面配置不穩定的原因

結果中,我們可以看到 LayoutShifts 自訂指標具有下列值:

[
  {
    "name": "",
    "entryType": "layout-shift",
    "startTime": 3087.2349999990547,
    "duration": 0,
    "value": 0.3422101449275362,
    "hadRecentInput": false,
    "lastInputTime": 0
  }
]

總而言之,在 3087 毫秒時,發生了 34.2% 的單一版面配置轉移。為協助找出原因,我們將使用 WebPageTest 的幻燈片檢視畫面

影格中的兩個儲存格,顯示版面配置位移前後的螢幕截圖。
幻燈片中的兩個儲存格,顯示版面配置位移前後的螢幕截圖。

捲動到影格的約 3 秒處,即可確切瞭解造成 34% 版面配置位移的原因:彩色表格。網站會非同步擷取 JSON 檔案,然後將其算繪至表格。表格一開始是空的,因此等待載入結果時填入表格會導致位移。

網頁字型標頭無故出現。
網頁字型標題無端出現。

但這還不是全部。當網頁在約 4.3 秒時視覺上已完成,我們可以看到網頁「Is my host fast yet?」的 <h1>突然出現。這是因為網站使用網頁字型,但未採取任何步驟來最佳化算繪作業。發生這種情況時,版面配置實際上不會位移,但使用者必須等待這麼久才能閱讀標題,仍會造成不良的使用體驗。

修正版面配置不穩定問題

我們現在知道非同步產生的表格會導致三分之一的檢視區塊位移,因此是時候修正這個問題了。在實際載入 JSON 結果之前,我們無法得知表格內容,但仍可使用某種預留位置資料填入表格,讓 DOM 呈現時的版面配置相對穩定。

以下是產生預留位置資料的程式碼:

function getRandomFiller(maxLength) {
  var filler = '█';
  var len = Math.ceil(Math.random() * maxLength);
  return new Array(len).fill(filler).join('');
}

function getRandomDistribution() {
  var fast = Math.random();
  var avg = (1 - fast) * Math.random();
  var slow = 1 - (fast + avg);
  return [fast, avg, slow];
}

// Temporary placeholder data.
window.data = [];
for (var i = 0; i < 36; i++) {
  var [fast, avg, slow] = getRandomDistribution();
  window.data.push({
    platform: getRandomFiller(10),
    client: getRandomFiller(5),
    n: getRandomFiller(1),
    fast,
    avg,
    slow
  });
}
updateResultsTable(sortResults(window.data, 'fast'));

系統會先隨機產生預留位置資料,再進行排序。包括重複隨機次數的「█」字元,用來建立文字的視覺預留位置,以及隨機產生的三個主要值分布。我也新增了一些樣式,將表格中的所有顏色去飽和,清楚指出資料尚未完全載入。

您使用的預留位置外觀不會影響版面配置穩定性。預留位置的目的是向使用者保證內容即將顯示,網頁並未損壞。

載入 JSON 資料時,預留位置會顯示如下:

資料表會以預留位置資料呈現。
資料表會以預留位置資料呈現。

解決網頁字型問題的程序簡單許多。由於網站使用 Google 字型,我們只需要在 CSS 要求中傳入 display=swap 屬性。就這樣,Fonts API 會在字型宣告中加入 font-display: swap 樣式,讓瀏覽器立即以備用字型算繪文字。以下是包含修正內容的對應標記:

<link href="https://fonts.googleapis.com/css?family=Chivo:900&display=swap" rel="stylesheet">

驗證最佳化項目

透過 WebPageTest 重新執行網頁後,我們可以產生前後比較,以視覺化方式呈現差異,並測量新的版面配置不穩定程度:

WebPageTest 影片格顯示兩個網站並排載入,一個經過版面配置最佳化,另一個則未經最佳化。
WebPageTest 影片格,並排顯示載入的兩個網站,分別有無進行版面配置最佳化。
[
  {
    "name": "",
    "entryType": "layout-shift",
    "startTime": 3070.9349999997357,
    "duration": 0,
    "value": 0.000050272187989256116,
    "hadRecentInput": false,
    "lastInputTime": 0
  }
]

根據自訂指標,版面配置位移仍發生在 3071 毫秒 (與先前大致相同),但位移嚴重程度大幅降低,只有 0.005%。我可以接受。

從影片格中也可以清楚看出,<h1> 字型會立即回復為系統字型,讓使用者更快讀取內容。

結論

複雜網站的版面配置位移次數可能比這個範例多,但修正程序仍相同:在 WebPageTest 中加入版面配置不穩定指標,參照結果和視覺載入膠卷,找出造成問題的原因,然後使用預留位置保留螢幕空間,藉此修正問題。

(One more thing) 測量實際使用者遇到的版面不穩定情形

能夠在最佳化前後對網頁執行 WebPageTest,並看到指標有所改善,固然是好事,但真正重要的是使用者體驗確實有所提升。這不就是我們想改善網站的原因嗎?

因此,如果我們開始測量實際使用者的版面配置不穩定體驗,以及傳統的網頁效能指標,那就太好了。這是最佳化意見回饋循環的重要環節,因為有了現場資料,我們才能瞭解問題所在,以及修正是否帶來正面影響。

除了收集自己的版面配置不穩定資料,您也可以查看 Chrome 使用者體驗報告,其中包含數百萬個網站的實際使用者體驗累積版面配置位移資料。您可以藉此瞭解自己 (或競爭對手) 的成效,也可以用來探索整個網路的版面配置不穩定狀態。