具代表性的面試主題

前端面試:如何用 View Transition API 做漸進增強的頁面轉場?

前端中等
Offer.cc 編輯團隊發佈 更新

題幹

請設計一個支援 SPA 與多頁導覽的 View Transition API 方案,並說明瀏覽器不支援、使用者偏好減少動效和轉場失敗時如何回退。

題幹與適用場景

產品希望在列表、詳情和篩選頁面之間提供連貫轉場,同時保留原生導覽、無障礙和低階裝置效能。請設計一個基於 View Transition API 的漸進增強方案:同文件更新使用 document.startViewTransition(),跨文件導覽使用 CSS 宣告,並說明 API 不可用、DOM 更新失敗或使用者開啟減少動效時的行為。

這道題適合前端、設計系統和效能工程職位。MDN、Chrome for Developers 與 CSS View Transitions 規範分別定義 ViewTransition 生命週期、同文件和跨文件機制、偽元素動畫樹及跳過轉場的方法。本文根據公開標準資料整理,不聲稱是公司真題。

面試官考察點

面試官關注你是否把「動畫效果」拆成導覽語意、DOM 更新、動畫生命週期和回退邊界。高品質回答會提到 readyupdateCallbackDonefinishedskipTransition()prefers-reduced-motion、唯一 view-transition-name 和同源限制;普通回答只會套一個淡入 CSS。

回答前需要釐清的問題

  • 目標是 SPA 內狀態切換、跨頁導覽,還是兩者都支援?
  • 哪些元素需要共享身份,列表卡片到詳情頁是否有穩定 ID?
  • 是否要求支援無 JavaScript 的核心導覽和搜尋引擎抓取?
  • 動畫時長、低階裝置預算和減少動效使用者的產品要求是什麼?

30 秒回答框架

「我會把原生導覽和狀態更新作為真源,View Transition 只做漸進增強。同文件用 startViewTransition(update) 包住同步或非同步 DOM 更新,等待 ready 後播放偽元素動畫;跨文件用 @view-transition { navigation: auto; } 並給共享元素穩定名稱。API 不存在、更新失敗或使用者偏好減少動效時直接完成導覽,必要時呼叫 skipTransition()。透過唯一命名、逾時和效能指標避免轉場阻塞業務。」

分步驟深入解答

同文件轉場先呼叫 document.startViewTransition(() => update())。瀏覽器擷取舊狀態,執行更新回呼,再生成新狀態;返回的 ViewTransition 提供 readyupdateCallbackDonefinished 等 Promise。更新回呼拋錯時,頁面狀態仍需由應用處理,不能把業務提交綁在動畫成功上。動畫可透過 ::view-transition-old(root)::view-transition-new(root) 等偽元素自訂。

共享元素使用 view-transition-name 建立舊節點與新節點的配對。名稱在同一棵轉場樹中應唯一;列表渲染必須用穩定業務 ID,不能把陣列索引當身份,否則排序或篩選會產生錯誤的飛行動畫。元素過多時只給關鍵節點命名,避免擷取和合成成本增長。

跨文件轉場依賴同源導覽和 CSS @view-transition 宣告,不需要 JavaScript 呼叫 startViewTransition()。它適合多頁應用或完整文件導覽,但受瀏覽器版本、同源策略和頁面 CSS 支援影響。導覽仍應能在沒有轉場的情況下完成,不能用動畫 Promise 阻塞伺服器回應或連結預設行為。

生命週期要有逾時與跳過路徑。ready 長時間未完成時記錄原因並呼叫 skipTransition();使用者點擊返回、提交表單或離開頁面時優先執行導覽。finished 只用於清理臨時狀態和指標,不應作為儲存資料的確認訊號。對非同步資料更新,先確定狀態提交邊界,再決定是否等待轉場。

無障礙策略包括尊重 @media (prefers-reduced-motion: reduce),在該媒體查詢下把動畫時長降為零或直接跳過;保持焦點、標題和閱讀順序,不用視覺位置取代語意更新。鍵盤使用者、螢幕閱讀器和慢速裝置都應取得相同內容結果。

漸進增強透過能力偵測和真實導覽回退實現。若 document.startViewTransition 不存在,就直接呼叫更新函式;跨文件不支援時保留普通連結。記錄支援率、跳過率、ready 延遲、動畫幀率和頁面互動延遲,按瀏覽器與裝置分層觀察。轉場只影響呈現,不改變快取、權限、表單提交或路由的正確性。

高品質示範回答

我會讓導覽和狀態提交獨立於動畫。SPA 使用 startViewTransition(update),在 ready 後只動畫必要的共享元素;多頁應用使用同源的 @view-transition 宣告。每個共享元素有穩定且唯一的業務名稱,非同步更新失敗時跳過轉場並展示正常錯誤狀態。

瀏覽器不支援時走原生更新或連結,prefers-reduced-motion 時關閉或壓縮動畫,生命週期設定逾時並保留 skipTransition()。焦點、標題和語意順序不依賴視覺效果。監控支援率、跳過率和互動延遲,灰度驗證後再擴大命名元素範圍。

常見錯誤

  • 錯誤表現 → 用陣列索引作為 view-transition-name失敗原因 → 排序後舊新節點錯誤配對;修正方法 → 使用穩定業務 ID 且保證名稱唯一。
  • 錯誤表現 → 等待 finished 才提交表單;失敗原因 → 動畫失敗會阻塞業務動作;修正方法 → 先提交狀態,動畫只負責呈現。
  • 錯誤表現 → 只寫 SPA 方案;失敗原因 → 多頁導覽沒有 API 呼叫入口;修正方法 →@view-transition 覆蓋同源跨文件導覽,並保留普通連結。
  • 錯誤表現 → 忽略減少動效偏好;失敗原因 → 給敏感使用者造成暈眩或認知負擔;修正方法 → 媒體查詢下縮短或跳過動畫。

追問及應對

更新回呼拋錯時,轉場和業務狀態如何處理?

把更新回呼視為業務狀態變更邊界,先保證異常可捕獲、狀態可回滾或展示錯誤;轉場 Promise 只用於動畫生命週期。若 updateCallbackDone reject,呼叫 skipTransition() 或讓瀏覽器結束預設呈現,不能把錯誤吞掉。

為什麼不能給所有元素都設定共享名稱?

每個名稱需要在舊樹和新樹中形成明確配對,數量過多會增加擷取、布局和合成成本,也可能製造錯誤匹配。只標記使用者能理解的關鍵物件,其餘內容使用根節點淡入或不動畫。

如何驗證轉場沒有損害效能?

分瀏覽器和裝置記錄 ready 延遲、動畫幀率、長工作、首次輸入延遲與跳過率,並用真實列表規模壓測。低階裝置或幀率持續下降時自動縮小動畫範圍或跳過,確保核心導覽耗時不變。

公開來源

同類題目