Communitygithub.com

Mad7droid/ux-motion

設計、實作與審查 UI 動畫,包含轉場、手勢、回饋與互動表面。在新增動畫或修復遲緩、卡頓、干擾的互動時使用。跳過非視覺工作與圖表動畫。

ux-motion 是什麼?

此技能提供一套結構化的規則與指南,用於在 UI 中設計與實作高品質的動畫。它基於「功能型 UI 通常落在 120–180ms 範圍」的核心原則,優先使用 named `transform` 與 `opacity` 轉場,避免使用 `transition: all`。技能詳細說明了何時該使用動畫(如空間連續性、狀態變更、輸入回饋)、如何選擇持續時間與 easing 曲線、如何保持渲染效能、以及如何正確處理手勢與中斷。它同時強調了對 `prefers-reduced-motion` 的支援,包含替代方案,並提供審查程式碼的表格格式。此技能適用於 Claude Code、Cursor 與 Codex 等 AI 代理,協助開發者在 React、CSS 或 JavaScript 專案中撰寫或審查 UI 動畫,特別是針對彈出層、選單、工具提示、Modal 與 Sheet 等常見覆蓋層。

相容平台✓Claude Code~Codex CLI~Cursor
npx skills add https://github.com/Mad7droid/mad-ux-motion/tree/main/skills/ux-motion

在你喜歡的 AI 中提問

開啟一個已預先載入此 Agent Skill 的新對話。

說明文件

UX 動畫

在設計與撰寫互動時應用這些規則。首先檢視專案的動畫代幣(token):儲存庫中的 AGENTS.md、CLAUDE.md、代幣檔案與設計文件會覆蓋下列預設值。

永遠啟用的核心

  • 預設決定:功能型 UI 通常落在 120–180ms 區間。專案代幣優先。
  • 為空間連續性、狀態變更、輸入回饋或避免突兀的彈出而製作動畫。
  • 優先使用 named transform 與 opacity 轉場。絕不要使用 transition: all。
  • 進入的表面應減速;退出的表面應加速。退出可以更短。
  • 縮放進入的表面從接近 scale(0.96) 開始,絕不從 scale(0) 開始。
  • 保持動畫可在 prefers-reduced-motion: reduce 下替換;保留理解性與鍵盤存取。
  • 為拖曳捕獲指標,防護次要觸控點,並在實際硬體上測試手勢。
  • 在撰寫動畫或觸碰常見覆蓋層之前,完整閱讀此檔案。僅在需要 clip paths、3D、WAAPI 或效能深入探討時才使用 REFERENCE.md。

1. 判斷是否值得使用動畫

將出現頻率作為限制條件:頻繁重複的動作應即時或近乎即時;偶爾出現的表面可以建立空間連續性;罕見的說明性時刻可以帶有更多個性。動畫必須用來釐清變更、確認輸入、保留位置或防止突兀的出現。如果沒有做到這些,就移除它。不要讓鍵盤快捷鍵等待裝飾性動畫。

2. 選擇持續時間

120–180ms 區間是預設決定:它刻意比 Material 3 公佈的 short3 (150ms)、short4 (200ms) 與標準轉場範圍 (250–400ms) 更緊湊。這表達了對慢速功能型 UI 的偏好,而非公佈的可及性或平台要求。

表面起點
按壓回饋100–140ms
工具提示或小型彈出視窗120–160ms
選單或下拉式選單140–180ms
Modal180ms
Sheet180ms;當移動大部分視窗時可達 250ms

退出的動畫使用較短的端點。這些是預設值,不是產品代幣的覆蓋值。

3. 選擇 easing

進入的表面應以強調感到達並穩定(減速);退出應迅速清除(加速)。Material 3 明確地命名這些方向:

:root {
  --ease-standard: cubic-bezier(0.2, 0, 0, 1);
  --ease-enter: cubic-bezier(0.05, 0.7, 0.1, 1); /* emphasized-decelerate */
  --ease-exit: cubic-bezier(0.3, 0, 0.8, 0.15); /* emphasized-accelerate */
}

僅在時間性進度中使用 linear。對於會經過刻意中間點的狀態,使用 ease-in-out 曲線。避免僅根據名稱選擇曲線:檢查繪製的形狀與移動方向。

4. 保持渲染低耗

優先使用 transform 與 opacity,它們可以停留在合成器上。指定屬性名稱,並讓佈局脫離動畫範圍。避免對 top、left、width、height、margin 或 padding 進行動畫,除非佈局變更就是重點且成本可接受。對於自適應高度,包裝器可以將 grid-template-rows: 0fr 轉場到 1fr,內部包裝器使用 min-height: 0 並由 overflow: hidden 裁剪。這仍然執行佈局;請對其進行效能剖析,而不是將其視為僅限合成器的捷徑。延後、簡短且僅在效能剖析顯示有幫助時才使用 will-change;圖層會消耗資源。

5. 確保狀態正確

  • 為可按壓的控制項提供可見回饋;使用現有的顏色、邊框或陰影狀態,或在合適時使用小幅度的 scale(0.98)。不要覆蓋定位用的 transform。
  • 保留可見的焦點、鍵盤啟動與停用行為。動畫不得延遲焦點放置、Escape 處理或語義狀態更新。
  • 彈出視窗、選單與工具提示透過 transform-origin 從錨點展開;置中的 Modal 從中心展開。在狀態變更時保持原點穩定。
  • 偏好使用轉場來處理可重複觸發的狀態。對自包含事件使用關鍵影格。
  • 使用 @media (hover: hover) and (pointer: fine) 來限制僅在懸停時提供的功能。
  • 對於進入的元素,在支援的地方使用 @starting-style,或使用一個掛載狀態,使初始樣式在轉場開始前可被觀察到。

6. 減少動畫意味著替代方案

prefers-reduced-motion 設定涵蓋動畫被移除、減少或替換的情況;大範圍平移與縮放可能觸發前庭系統。在仍能解釋狀態的地方,將移動與縮放替換為透明度與顏色變化。保持焦點、載入與可見性變更易於理解。不要僅因為使用者要求減少動畫就讓元素消失。在 JavaScript 驅動的動畫與 CSS 中都尊重此偏好,包括在頁面開啟時偏好變化的情況。不要依賴 transitionend 事件來完成必要的狀態變更:轉場可能被停用或取消。將覆蓋範圍限定在受影響的元件,而不是全域地強制所有動畫使用極短的持續時間。

7. 手勢

在拖曳開始時呼叫 setPointerCapture():後續的指標事件將繼續目標鎖定該捕獲元素,直到釋放。根據調整過的速度或距離規則來關閉;沒有通用的滑動常數,因此請在實際裝置上校準。使用阻尼來限制移動範圍,而不是硬邊界。一旦手勢擁有指標,就忽略其他觸控點。允許使用者反轉進行中的手勢。透過清除拖曳狀態來處理 pointercancel 與 lostpointercapture。為手勢軸選擇 touch-action,避免不必要地阻擋頁面滾動;提供按鈕或鍵盤等效操作。

8. 處理中斷與彈簧

快速開啟 / 關閉 / 重新開啟應穩定在最新請求的狀態。從當前視覺狀態重新定位目標,而不是從頭開始重播。在取代或卸載時取消陳舊的回呼、監聽器與動畫;舊的退出動畫不得移除新開啟的表面。根據元件的焦點生命週期,將隱藏或正在退出的內容排除在鍵盤導航之外。

當直接操作或連續性從中受益時使用彈簧,並尊重專案的函式庫。彈簧參數在不同引擎之間有所不同:不要盲目複製 stiffness 與 damping 值。在實際元件上調整穩定時間與 overshoot;避免在文字密集的表面上彈跳,並在減少動畫情況下停用移動。

9. 在宣告完成前驗證

以 4 倍慢速重播,檢查屬性是否同時完成並從正確的位置開始。快速切換以暴露卡頓。在 DevTools 中模擬減少動畫。將拖曳操作用到邊緣、取消它、加入第二個觸控點,並在實體裝置上測試。對於執行時期計算的動畫值,請查閱 REFERENCE.md。說明實際執行了哪些檢查,以及哪些需要瀏覽器或實體裝置;僅靠程式碼審查無法確定感知的平滑度。

審查輸出

在稽核程式碼時,以一個緊湊的表格報告,最嚴重的優先:

檔案:行數現狀變更為原因
Menu.tsx:18transition: all 300msnamed 屬性與專案代幣避免意外的佈局動畫

僅報告在程式碼中可見的發現。如果 diff 是乾淨的,請直接說明,而不是憑空捏造發現。

由 mad7droid 策劃。

相關技能