題幹與適用場景
產品希望在列表、詳情和篩選頁面之間提供連貫轉場,同時保留原生導覽、無障礙和低階裝置效能。請設計一個基於 View Transition API 的漸進增強方案:同文件更新使用 document.startViewTransition(),跨文件導覽使用 CSS 宣告,並說明 API 不可用、DOM 更新失敗或使用者開啟減少動效時的行為。
這道題適合前端、設計系統和效能工程職位。MDN、Chrome for Developers 與 CSS View Transitions 規範分別定義 ViewTransition 生命週期、同文件和跨文件機制、偽元素動畫樹及跳過轉場的方法。本文根據公開標準資料整理,不聲稱是公司真題。
面試官考察點
面試官關注你是否把「動畫效果」拆成導覽語意、DOM 更新、動畫生命週期和回退邊界。高品質回答會提到 ready、updateCallbackDone、finished、skipTransition()、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 提供 ready、updateCallbackDone 和 finished 等 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 延遲、動畫幀率、長工作、首次輸入延遲與跳過率,並用真實列表規模壓測。低階裝置或幀率持續下降時自動縮小動畫範圍或跳過,確保核心導覽耗時不變。