在 Next.js 支持的電子商務網站中解決 CLS 問題(案例研究)

已發表: 2022-03-10
快速總結↬ Cumulative Layout Shift 是最難調試的核心 Web 之一。 在本文中,我們通過不同的工具來研究 CLS、何時使用它們(何時不使用),以及我們在基於 Next.js 的電子商務網站中遇到的一些 CLS 問題的解決方案。

Fairprice 是新加坡最大的在線雜貨店之一。 我們一直在尋找機會來改善用戶的在線購物體驗。 性能是確保我們的用戶無論使用何種設備或網絡連接都能獲得令人愉悅的用戶體驗的核心方面之一。

有許多關鍵性能指標 (KPI) 可以衡量網頁生命週期中的不同點(例如 TTFB、 domInteractiveonload ),但這些指標並不能反映最終用戶對頁面的體驗。

我們想使用一些與最終用戶實際體驗密切對應的 KPI,因此我們知道,如果其中任何一個 KPI 表現不佳,那麼它將直接影響最終用戶體驗。 我們發現以用戶為中心的性能指標非常適合此目的。

有許多以用戶為中心的性能指標來衡量頁面生命週期中的不同點,例如 FCP、LCP、FID、CLS 等。 對於本案例研究,我們將主要關注 CLS。

CLS 測量頁面開始加載到卸載之間發生的所有意外佈局轉換的總分。

因此,具有較低的 CLS 值的頁面可確保沒有隨機的佈局變化導致用戶沮喪。 Barry Pollard 寫了一篇關於 CLS 的優秀的深入文章。

我們如何在產品頁面中發現 CLS 問題

我們使用 Lighthouse 和 WebPagetest 作為我們的綜合測試工具來衡量 CLS 的性能。 我們還使用 web-vitals 庫來衡量真實用戶的 CLS。 除此之外,我們還會查看 Google Search Console Core Web Vitals 報告部分,以了解我們任何頁面中的任何潛在 CLS 問題。 在探索報告部分時,我們發現產品詳細信息頁面中的許多 URL 的 CLS 值超過0.1 ,這表明那裡發生了一些重大的佈局轉換事件。

跳躍後更多! 繼續往下看↓

使用不同工具調試 CLS 問題

現在我們知道產品詳細信息頁面上存在 CLS 問題,下一步是確定導致該問題的元素。 起初,我們決定使用綜合測試工具運行一些測試。

所以我們運行燈塔檢查它是否能找到任何可能觸發重大佈局轉變的元素,它報告 CLS 為 0.004,非常低。

CLS 是 0.004
CLS 顯示低 CLS 結果為.004 。 (大預覽)

Lighthouse 報告頁面有一個診斷部分。 這也沒有顯示任何導致高 CLS 值的元素。

燈塔報告頁面
報告頁面的預覽,包括 CLS 貢獻結果。 (大預覽)

然後我們運行 WebpageTest 並決定檢查幻燈片視圖:

幻燈片視圖
幻燈片視圖以黃色虛線顯示具有視覺變化和佈局偏移的任何幀。 (大預覽)

我們發現此功能非常有用,因為我們可以找出哪個元素在哪個時間點導致佈局發生變化。 但是當我們運行測試以查看是否突出顯示任何佈局變化時,沒有任何東西對巨大的 LCS 有任何貢獻:

測試以查看哪個元素在哪個時間點導致了佈局偏移
只需快速瀏覽一下框架,您就可以了解是否發生了任何佈局變化。 (大預覽)

CLS 的怪癖是它在頁面的整個生命週期中記錄單個佈局轉換分數並添加它們。

注意自 2021 年 6 月起,CLS 的測量方式發生了變化。

由於 Lighthouse 和 WebpageTest 無法檢測到任何觸發重大佈局變化的元素,這意味著它發生在初始頁面加載之後可能是由於某些用戶操作。 所以我們決定使用 Web Vitals Google Chrome 擴展,因為它可以在用戶與之交互時在頁面上記錄 CLS。 在執行不同的操作後,我們發現當用戶使用圖像放大功能時,佈局偏移分數正在增加。

為了交叉驗證鼠標懸停在圖像上時是否發生佈局移位,我們使用了來自 https://web.dev/cls/ 的以下代碼片段,它在發生佈局移位時添加了console.log

 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});

在進一步調查中,我們發現 ASDA 面臨類似的問題,並針對 chrome 提出了該問題。

根本原因

在產品詳細信息頁面上,用戶可以將鼠標移到產品圖像上,以與實際產品圖像並排查看圖像的放大部分,因為該視頻準確地顯示了我們正在談論的內容。

圖像放大功能幫助我們的用戶獲得產品的外觀和感覺,並確保它是他們想要購買的產品的正確變體。

我們已經使用react-image zoom庫來構建這個圖像放大功能。

Image Magnify 庫通常有一個鏡頭(當鼠標在圖像中移動時移動的正方形)。 由於此鏡頭隨著鼠標移動而改變其頂部和左側位置,因此它被檢測為觸發 CLS 的佈局移位。 我們檢查了庫頁面以及其他類似的 React 庫( react-image-magnifyreact-image-zoomreact-image-magnifiers ),發現它們都存在相同的 CLS 問題。

我們如何修復它

我們注意到react-image-zoom正在使用js-image-zoom庫。 所以我們不得不修改js-image zoom庫來解決這個問題。

解決方案非常簡單。 當鼠標在產品圖像上移動時,圖像鏡頭元件通過改變其左側和頂部位置來移動。 為了解決這個問題,我們使用了transform translate將元素移動到一個新層,即在這個新層上發生的任何移動都不會再導致佈局移位:

使用變換轉換管理鏡頭運動
(大預覽)

我還為原始存儲庫創建了一個 PR,以便使用此庫的其他開發人員可以擺脫 CLS 問題。

為原始倉庫創建 PR
公關創建幫助擺脫 CLS 問題。 (大預覽)

變化的影響

代碼部署到生產環境後,CLS 被固定在產品詳情頁面,受 CLS 影響的頁面數量減少了 98%:

顯示更改影響的圖形。
與使用 left 和 top 的位置操作相比, transform具有性能優勢。 (大預覽)

由於我們使用了transform ,它還有助於使圖像放大給用戶帶來更流暢的體驗。

注意Paul Irish 寫了一篇關於這個主題的優秀文章。

我們為 CLS 所做的其他關鍵更改

在我們網站的許多頁面中,我們還遇到了一些其他有助於 CLS 的問題。 讓我們來看看這些元素和組件,看看我們如何嘗試減輕由它們引起的佈局變化。

  • 網絡字體:
    我們注意到,字體的延遲加載會導致用戶感到沮喪,因為內容會閃爍,並且還會導致一些佈局變化。 為了盡量減少這種情況,我們做了一些更改:

    • 我們已經自行託管了字體,而不是從第 3 方 CDN 加載。
    • 我們預加載字體。
    • 我們使用字體顯示可選。
  • 圖片:
    圖像中缺少高度或寬度值會導致圖像後的元素在圖像加載後發生移動。 這最終成為 CLS 的主要貢獻者。 由於我們使用的是 Next.js,因此我們利用了名為next/images的內置圖像組件。 該組件包含幾個與圖像相關的最佳實踐。 它建立在<img> HTML 標籤之上,可以幫助改進 LCP 和 CLS。 我強烈建議閱讀此 RFC,以了解使用它的關鍵特性和優勢。

  • 無限滾動:
    在我們的網站上,產品列表頁面可以無限滾動。 因此,最初,當用戶滾動到頁面底部時,他們會在加載下一組數據之前看到頁腳的幾分之一秒,這會導致佈局發生變化。 為了解決這個問題,我們採取了幾個步驟:

    • 我們甚至在用戶到達列表的絕對底部之前調用 API 來加載數據。
    • 我們為加載狀態預留了足夠的空間,並在加載狀態顯示產品骨架。 所以現在當用戶滾動時,他們在加載產品的幾秒鐘內看不到頁腳。

Addy Osmani 寫了一篇關於這種方法的詳細文章,我強烈建議您查看。

關鍵要點

  • 雖然 Lighthouse 和 WebpageTest 有助於發現頁面加載前發生的性能問題,但它們無法檢測頁面加載後的性能問題。
  • Web Vitals 擴展可以檢測由用戶交互觸發的 CLS 更改,因此如果頁面具有高 CLS 值但 Lighthouse 或 WebpageTest 報告低 CLS,則 Web Vitals 擴展可以幫助查明問題。
  • Google Search Console 數據基於真實用戶的數據,因此也可以指出頁面生命週期中任何時候發生的潛在性能問題。 一旦檢測到並修復了問題,再次檢查報告部分可以幫助驗證性能修復的有效性。 這些更改會在幾天內反映在 Web Vitals 報告部分中。

最後的想法

雖然 CLS 問題相對難以調試,但在頁面加載(Lighthouse、WebPageTest)和 Web Vitals 擴展(頁面加載後)之前使用不同工具的組合可以幫助我們查明問題。 它也是正在經歷大量積極開發以涵蓋廣泛場景的指標之一,這意味著它的衡量方式將在未來發生變化。 我們正在關注 https://web.dev/evolving-cls/ 以了解任何即將發生的變化。

至於我們,我們也在不斷努力改進其他 Core Web Vitals。 最近,我們實現了響應式圖像預加載並開始以 WebP 格式提供圖像,這幫助我們減少了 75% 的圖像負載,減少了 62% 的 LCP,以及 24% 的速度指數。 您可以閱讀有關改進 LCP 和速度指數的優化的更多詳細信息,或關注我們的工程博客以了解我們正在進行的其他令人興奮的工作。

我們要感謝 Alex Castle 幫助我們調試產品頁面上的 CLS 問題並解決了next/images實現中的怪癖。