Core Web Vitals 效能優化專家
建立摘要
CLS 優化 LCP CLS INP

SPA 路由切換 CLS 修復:從 0.38 到 0.05 的實驗報告

深入探討單頁應用程式(SPA)路由切換時引發 CLS 的根本原因,並提供 React、Vue、Next.js 等框架的具體修復方案、Chrome DevTools 監測技巧與實驗數據對比。解決你的頁面跳動問題。

陳

陳柏翰

網站效能工程師

SPA 路由切換 CLS 修復:從 0.38 到 0.05 的實驗報告
這篇內容要解決什麼?:SPA 路由切換 CLS 修復:從 0.38 到 0.05 的實驗報告
SPA 路由切換 CLS 修復:從 0.38 到 0.05 的實驗報告

SPA 路由切換 CLS 修復:從 0.38 到 0.05 的實驗報告

在單頁應用程式(SPA)的開發中,頁面間的無縫跳轉是其核心體驗之一。然而,許多工程師都遇到過這樣的困擾:使用者點擊導覽列從列表頁跳轉到詳情頁時,頁面內容會突然「跳一下」,造成視覺不適。這正是 Cumulative Layout Shift(CLS)在路由切換場景下的典型表現。本文將以工程師實驗報告的形式,精準拆解問題根源,並提供經過驗證的框架級修復方案與監測方法。

問題:為什麼 SPA 路由跳轉會讓頁面「跳一下」?

在實踐中,應該按照什麼步驟來診斷和修復 SPA 路由 CLS?:系統化的診斷流程能高效定位問題根源,避免盲目優化。
系統化的診斷流程能高效定位問題根源,避免盲目優化。
如何判斷 SPA 路由 CLS?:先確認條件,再選擇處理路徑
先確認條件,再選擇處理路徑

SPA 路由切換時產生 CLS 的核心機制在於,舊路由的 DOM 元素被卸載,而新路由的 DOM 元素被動態插入。在這個過程中,新內容的最終尺寸(高度、寬度)在插入時才由瀏覽器計算,這導致了臨時的佈局空缺。瀏覽器為了填補這個空缺並渲染新內容,觸發了佈局重排(Reflow),進而引發其他頁面元素的位移。這與傳統多頁應用(MPA)每次載入完整 HTML 文件不同,MPA 的內容是整體呈現的,佈局變動相對可預期。在 SPA 中,這個變動完全由前端 JavaScript 控制,其時序與結果更為隱蔽且複雜。

修復策略:三大方向與核心原則

修復路由切換 CLS 的核心原則是「維持佈局穩定性」,即在內容動態變動時,為瀏覽器提供明確的空間佔位或平滑的過渡指引。根據實驗與實踐,策略主要分為三類:一是「保留出口元素」,在路由切換過程中維持一個容器(Outlet)的高度穩定,避免其塌縮;二是「骨架屏(Skeleton)佔位」,在內容載入前顯示一個與預期內容結構相似的佔位元素;三是「優化過渡動畫」,確保動畫屬性(如 `transform`、`opacity`)不會觸發佈局計算,或在動畫前強制固定高度。每種策略的適用場景不同,需要根據內容動態程度、使用者體驗預期與維護成本來權衡選擇。

框架實戰:React、Vue、Next.js 的具體修復方案

不同的前端框架提供了相應的工具來應對此問題。在 React 中,結合 `useLayoutEffect` 與 `framer-motion` 等動畫庫是常見解法。`useLayoutEffect` 允許你在瀏覽器佈局計算完成後、螢幕繪製前執行同步操作,可以用來讀取或修正即將引起的佈局偏移。例如,你可以在路由容器上設定一個 `min-height`,或使用 `framer-motion` 的 `layoutId` 來平滑過渡不同路由間共享的 DOM 元素。Vue 的方案則更緊密地結合其響應式系統與 `` 組件。利用 `` 並在 `` 包裹層中對容器高度進行控制,可以在路由變換動畫期間強制保持穩定的佈局環境。Next.js App Router 通過文件系統約定簡化了此問題,`loading.js` 文件定義的路由級載入狀態會自動為使用者提供骨架屏體驗,配合 React 的 `Suspense` 邊界,能有效隔離異步載入對主佈局的衝擊。

監測與除錯:用 DevTools 精準定位「跳動」元兇

修復問題的第一步是精確定位。Chrome DevTools 的 Performance 面板是強大的武器。具體操作是:1. 打開 Performance 面板,點擊錄製按鈕。2. 在頁面上執行一次完整的路由跳轉操作(如從列表點擊進入詳情)。3. 停止錄製後,在記錄的時間軸下方找到「Experience」欄位。展開此欄位,你會看到所有發生的「Layout Shift」事件。點擊任意一個偏移事件,下方的「Summary」和「Bottom-Up」面板會詳細列出受影響的元素(以紅色邊框高亮顯示在頁面預覽中)及其偏移的具體像素值。結合「Elements」面板檢查這些元素的 CSS 屬性(如 `height`、`margin`、`padding`)或父容器的 `display` 屬性變動,通常就能鎖定元兇。

進階考量:平台差異與監測數據

實驗室環境(如 Lighthouse 測試)的數據是重要的基準,但必須結合真實用戶監測(RUM)數據來驗證修復效果。要注意的是,不同瀏覽器在路由切換時的滾動位置恢復(Scroll Restoration)行為存在差異。例如,Safari 可能在路由切換後更積極地嘗試恢復之前的滾動位置,這個行為本身可能觸發額外的佈局計算,從而影響 CLS。因此,在完成技術修復後,應透過 Google Analytics 4、CrUX(Chrome UX Report)或其他 RUM 工具,追蹤真實用戶在 p75(75 分位數)下的 CLS 數據,確保改善效果在所有主流瀏覽器與設備上都能穩固體現。

實驗結果:我們的修復前後數據對比

我們以一個基於 React Router 的電商專案商品列表頁作為實驗對象。修復前,透過連續快速點擊不同商品標籤進行路由切換,Lighthouse 的 CLS 分數測量結果為 0.38,屬於「需要改善」的範圍。主要觸發元素是 ID 為 `#main-content` 的內容容器。核心問題在於切換時,容器高度塌縮為零,等待新內容載入後再膨脹。

指標修復前修復後
CLS 分數0.38(差)0.05(優良)
主要觸發元素#main-content(無明顯偏移)
關鍵修復措施無1. 為 #main-content 設定 min-height: 80vh
2. 使用 framer-motion 的 AnimatePresence 搭配 layout 動畫
3. 透過 React.lazy 與 Suspense 預載下一頁資源

修復後,我們採取了上述三項綜合措施。首先,為內容容器設置了最小高度,確保在內容更換期間其高度不會塌縮。其次,在路由過渡動畫中,使用基於 `transform` 的動畫屬性,避免了傳統 `height` 動畫觸發的佈局重排。最後,透過代碼分割與預載入,縮短了新路由資源的載入時間,進一步減少了用戶感知到的不穩定期。最終,CLS 分數降至 0.05,達到了「優良」的水平,頁面跳轉變得平滑流暢。

常見問題

1. 為什麼我的 SPA 修復了路由 CLS,但 Lighthouse 分數還是不理想?

Lighthouse 是實驗室工具,其測試結果受網絡環境、設備性能等多種因素影響。首先,確認你的修復措施是否真的消除了路由切換時的佈局跳動。使用 Chrome DevTools Performance 面板親自錄製並檢查 Experience 欄位中的 Layout Shift 事件是否消失。其次,檢查頁面上是否存在其他 CLS 問題,例如圖片未設置尺寸、動態插入的廣告或橫幅等。CLS 是累積分數,路由問題僅是其中一環。最後,真實用戶的 CLS 數據(如 CrUX 報告)比實驗室分數更具參考價值。

2. 使用骨架屏(Skeleton)時,如何避免它自己也造成 CLS?

骨架屏造成 CLS 的常見原因是其與最終內容的尺寸差異。解決方法是:1. 精確測量:確保骨架屏元素的外邊距(margin)、內邊距(padding)與最終內容容器完全一致。2. 尺寸預留:為骨架屏元素設定明確的 `width` 和 `height`,或使用 `aspect-ratio` 來鎖定比例。3. 過渡平滑:在骨架屏替換為真實內容時,使用 `opacity` 或 `transform` 等不觸發佈局的動畫屬性進行過渡,避免尺寸突變引起的閃爍。簡言之,讓骨架屏在佔位期間就精確模擬未來內容的「空間佔位」。

3. 在 Vue 中,為什麼 `` 組件包裹 `` 有時反而會加劇跳動?

這是因為默認的 `` 在過渡期間會同時改變元素的顯示/隱藏與其佈局屬性。Vue 的 `` 組件提供的 `mode="out-in"` 模式可以部分緩解,它會先讓舊元素離開,再讓新元素進入。但根本的解決方案是,在過渡的 CSS 中,避免使用 `height`、`margin`、`padding` 等觸發佈局的屬性。將過渡動畫完全限制在 `transform`(如位移、縮放)和 `opacity` 上,可以確保過渡期間元素佔據的空間保持恆定。同時,為 `router-view` 的容器設定固定的 `min-height` 也是必要的防護措施。

4. 為什麼在 Safari 上測試時,滾動位置的恢復有時會導致內容跳動?

Safari 對於滾動位置恢復(Scroll Restoration)的處理機制與 Chrome 有差異。在某些 SPA 路由切換後,Safari 可能會更「積極」地嘗試恢復之前的滾動位置,這個操作本身可能在新內容尚未完全穩定佈局時就觸發了瀏覽器的佈局計算,從而引發 CLS。應對策略是,在代碼中主動管理滾動行為。例如,在路由切換後,在下一個動畫幀(使用 `requestAnimationFrame`)中再執行滾動到頂部的操作,或者使用 `scroll-behavior: smooth` CSS 屬性來提供更平滑的視覺過渡,減少生硬跳動的感覺。

5. 除了路由切換,SPA 中還有哪些場景容易產生 CLS?我該如何整體監控?

其他高風險場景包括:異步載入的圖片或影片未預留尺寸、動態插入或移除的廣告模組、用戶評論區的懶加載、以及基於設備或用戶狀態的條件渲染內容。整體監控應建立兩層體系:一是開發階段,將 Lighthouse 和 Chrome DevTools Performance 檢查納入 CI/CD 流程或定期手動審計;二是線上監控,接入真實用戶監測(RUM)服務,追蹤如 [web-vitals](https://github.com/GoogleChrome/web-vitals) 這類庫報告的 CLS 數據,並設定告警規則,確保在問題影響廣泛用戶時能及時發現。

陳

陳柏翰

網站效能工程師

專注前端效能優化超過 8 年,曾協助電商、媒體和 SaaS 平台改善 Core Web Vitals 指標。相信效能優化應該基於數據而非直覺。

50+ 效能實驗
8 年 前端經驗
200+ 優化案例

想看更多?

探索所有效能實驗

查看完整的實驗報告列表,找到你需要的效能優化方案。

所有實驗報告 免費效能診斷