SKILL.md
readonlyread-only
name
fixing-motion-performance
description
稽核並修復動畫效能問題,包括版面抖動、合成器屬性、與滾動連動的動畫以及模糊效果。當動畫卡頓、轉場不流暢,或審查 CSS/JS 動畫效能時使用。
fixing-motion-performance
修復動畫效能問題。
使用方式
-
/fixing-motion-performance
將這些限制套用至本次對話中的所有 UI 動畫工作。 -
/fixing-motion-performance <file>
根據以下所有規則審查該檔案,並回報:- 違規項目(引用確切的行或片段)
- 為什麼重要(一句簡短說明)
- 具體的修正方式(程式碼層級的建議)
除非明確要求,否則不要遷移動畫函式庫。在現有技術堆疊內套用規則。
何時套用
在以下情況參考這些指南:
- 新增或修改 UI 動畫(CSS、WAAPI、Motion、rAF、GSAP)
- 重構卡頓的互動或轉場
- 實作與滾動連動的動畫或滾動顯示效果
- 對版面、濾鏡、遮罩、漸層或 CSS 變數進行動畫
- 審查使用了 will-change、transform 或尺寸測量的元件
渲染步驟詞彙
- composite:transform、opacity
- paint:顏色、邊框、漸層、遮罩、圖片、濾鏡
- layout:尺寸、位置、流向、grid、flex
規則類別(依優先順序)
| 優先順序 | 類別 | 影響 |
|---|---|---|
| 1 | 禁止模式 | 嚴重 |
| 2 | 選擇機制 | 嚴重 |
| 3 | 測量 | 高 |
| 4 | 滾動 | 高 |
| 5 | paint | 中高 |
| 6 | 圖層 | 中 |
| 7 | 模糊與濾鏡 | 中 |
| 8 | 視圖轉場 | 低 |
| 9 | 工具邊界 | 嚴重 |
快速參考
1. 禁止模式(嚴重)
- 不要在相同影格中交錯進行版面讀取與寫入
- 不要對大型或重要表面持續進行版面動畫
- 不要透過 scrollTop、scrollY 或 scroll 事件驅動動畫
- 沒有停止條件的 requestAnimationFrame 迴圈
- 不要混用多個各自測量或變更版面的動畫系統
2. 選擇機制(嚴重)
- 預設使用 transform 與 opacity 進行動畫
- 僅在互動需要時使用 JS 驅動的動畫
- paint 或 layout 動畫僅可接受在小型、孤立的表面上
- 一次性效果比連續動畫更容易被接受
- 偏好降級技術而非完全移除動畫
3. 測量(高)
- 測量一次,然後透過 transform 或 opacity 進行動畫
- 在寫入前批次處理所有 DOM 讀取
- 不要在動畫期間重複讀取版面
- 偏好 FLIP 風格的轉場來實現類似版面的效果
- 偏好能批次處理測量與寫入的方法
4. 滾動(高)
- 偏好使用 Scroll 或 View Timelines 來實現與滾動連動的動畫(若可用)
- 使用 IntersectionObserver 來控制可見性與暫停
- 不要為了動畫而輪詢滾動位置
- 當元件離開畫面時暫停或停止動畫
- 與滾動連動的動畫不得在大型表面上觸發連續的 layout 或 paint
5. paint(中高)
- 觸發 paint 的動畫僅允許在小型、孤立的元素上
- 不要在大型容器上對 paint 密集型屬性進行動畫
- 不要對 transform、opacity 或 position 的 CSS 變數進行動畫
- 不要對繼承的 CSS 變數進行動畫
- 將動畫用的 CSS 變數限定在區域範圍內,避免繼承
6. 圖層(中)
- 合成器動畫需要圖層提升,切勿假設已存在
- 暫時且精準地使用 will-change
- 避免大量或大型的提升圖層
- 當效能重要時,使用工具驗證圖層行為
7. 模糊與濾鏡(中)
- 保持模糊動畫範圍小(<=8px)
- 僅在短暫、一次性效果中使用模糊
- 切勿對模糊進行連續動畫
- 切勿在大型表面上對模糊進行動畫
- 在模糊之前優先使用 opacity 與 translate
8. 視圖轉場(低)
- 僅在導航層級的變更中使用視圖轉場
- 避免在互動密集的 UI 中使用視圖轉場
- 當需要中斷或取消時,避免使用視圖轉場
- 將尺寸變更視為可能觸發 layout 的操作
9. 工具邊界(嚴重)
- 除非明確要求,否則不要遷移或重寫動畫函式庫
- 在現有動畫系統內套用這些規則
- 切勿在同一元件中部分遷移 API 或混用樣式
常見修正
/* 版面抖動:改用 transform 取代 width 進行動畫 */
/* 修改前 */ .panel { transition: width 0.3s; }
/* 修改後 */ .panel { transition: transform 0.3s; }
/* 與滾動連動:使用 scroll-timeline 取代 JS */
/* 修改前 */ window.addEventListener('scroll', () => el.style.opacity = scrollY / 500)
/* 修改後 */ .reveal { animation: fade-in linear; animation-timeline: view(); }
// 測量:在寫入前批次讀取(FLIP)
// 修改前 — 版面抖動
el.style.left = el.getBoundingClientRect().left + 10 + 'px';
// 修改後 — 測量一次,透過 transform 動畫
const first = el.getBoundingClientRect();
el.classList.add('moved');
const last = el.getBoundingClientRect();
el.style.transform = `translateX(${first.left - last.left}px)`;
requestAnimationFrame(() => { el.style.transition = 'transform 0.3s'; el.style.transform = ''; });
審查指引
- 優先執行嚴重規則(禁止模式、工具邊界)
- 選擇符合意圖且渲染成本最低的方式
- 對於任何非預設的選擇,說明其合理限制(表面大小、持續時間或互動需求)
- 審查時,偏好提供可操作的註解與具體替代方案,而非理論說明






