動畫系統架構師 是做什麼的?
使用 Framer Motion、GSAP、View Transitions API 和彈簧物理學,建立高效能且無障礙的動畫系統,以實現流暢的 UI 體驗。
啟動觸發器
啟用於:頁面轉換、佈局動畫、滾動觸發動畫、微互動、彈簧物理學、motion.div、gsap.to、View Transition API、共享元素轉換、交錯列表動畫。
不適用於:僅 CSS 懸停/焦點效果 -- 請使用 css-in-js-architect。Canvas/WebGL 渲染 -- 請使用 creative-coding-expert。Lottie 檔案播放 -- 請使用標準 Lottie 整合。
快速開始
- 選擇你的引擎 -- 對 React 聲明式使用 Framer Motion,對時間軸密集型或非 React 使用 GSAP,對跨頁面導航使用 View Transitions API。
- 僅對變換和不透明度進行動畫 -- 這些在合成執行緒(GPU)上運行,避免佈局抖動。
- 適度使用
will-change-- 僅在即將動畫的元素上使用,完成後移除。 - 尊重
prefers-reduced-motion-- 對請求它的用戶禁用或簡化所有動畫。 - 使用 DevTools 進行效能分析 -- 在效能標籤頁中檢查動畫期間的佈局變化。
核心能力
| 領域 | 技術 | 關鍵模式 |
|---|---|---|
| 聲明式 React | Framer Motion 11+,motion 元件 | 佈局動畫,AnimatePresence,變體 |
| 時間軸動畫 | GSAP 3.12+,ScrollTrigger | 滾動驅動序列,固定,擦除 |
| 頁面轉換 | View Transitions API,Next.js useViewTransition | 跨頁面共享元素轉換 |
| 彈簧物理學 | Framer Motion 彈簧,react-spring | 自然緩動,可中斷動畫 |
| 微互動 | CSS 轉換 + Framer Motion | 按鈕回饋,懸停狀態,載入指示器 |
| 滾動驅動 | CSS animation-timeline: scroll(),GSAP ScrollTrigger | 視差,進度指示器,滾動時揭示 |
架構模式
模式 1:Framer Motion 佈局動畫
import { motion, AnimatePresence, LayoutGroup } from 'framer-motion';
function FilterableGrid({ items, filter }: Props) {
const filtered = items.filter(item => item.category === filter);
return (
<LayoutGroup>
<motion.div layout className="grid grid-cols-3 gap-4">
<AnimatePresence mode="popLayout">
{filtered.map(item => (
<motion.div
key={item.id}
layout // 為位置變化添加動畫
initial={{ opacity: 0, scale: 0.8 }}
animate={{ opacity: 1, scale: 1 }}
exit={{ opacity: 0, scale: 0.8 }}
transition={{ type: 'spring', stiffness: 300, damping: 25 }}
>
<Card item={item} />
</motion.div>
))}
</AnimatePresence>
</motion.div>
</LayoutGroup>
);
}
模式 2:用於頁面導航的 View Transitions API
// app/components/TransitionLink.tsx
'use client';
import { useRouter } from 'next/navigation';
import { useCallback } from 'react';
export function TransitionLink({ href, children }: { href: string; children: React.ReactNode }) {
const router = useRouter();
const handleClick = useCallback((e: React.MouseEvent) => {
e.preventDefault();
if (!document.startViewTransition) {
router.push(href);
return;
}
document.startViewTransition(() => {
router.push(href);
});
}, [href, router]);
return <a href={href} onClick={handleClick}>{children}</a>;
}
/* 透過 view-transition-name 實現共享元素轉換 */
.product-image {
view-transition-name: product-hero;
}
::view-transition-old(product-hero) {
animation: fade-and-scale 0.3s ease-out;
}
::view-transition-new(product-hero) {
animation: fade-and-scale 0.3s ease-in reverse;
}
模式 3:尊重減少動作偏好
import { useReducedMotion } from 'framer-motion';
function AnimatedComponent() {
const shouldReduce = useReducedMotion();
return (
<motion.div
initial={{ opacity: 0, y: shouldReduce ? 0 : 20 }}
animate={{ opacity: 1, y: 0 }}
transition={shouldReduce
? { duration: 0 }
: { type: 'spring', stiffness: 260, damping: 20 }
}
>
內容
</motion.div>
);
}
┌─ 動畫決策樹 ──────────────────────────────────┐
│ │
│ prefers-reduced-motion? │
│ ├── 是 → 僅即時淡入淡出(無運動) │
│ └── 否 → 完整彈簧/變換動畫 │
│ │
│ 正在動畫什麼? │
│ ├── transform/opacity → GPU 合成執行緒(良好) │
│ ├── width/height → 佈局抖動(避免) │
│ └── box-shadow → 僅繪製(可接受) │
└───────────────────────────────────────────────────┘
反模式
- 對
width、height、top、left進行動畫 -- 每幀都會觸發佈局重新計算。改用transform: translate/scale以達到 60fps。 - 對每個元素使用
will-change-- 會將太多圖層提升到 GPU,增加記憶體使用量。僅在即將動畫的元素上應用。 - 忽略
prefers-reduced-motion-- 對動作敏感的用戶會感到噁心或癲癇。務必檢查並尊重此媒體查詢。 - 微互動的動畫持續時間 > 500ms -- 會讓 UI 感覺遲緩。保持按鈕/懸停回饋在 200ms 以下,頁面轉換在 400ms 以下。
- 在滾動期間不使用
requestAnimationFrame或 ScrollTrigger 進行動畫 -- 會導致卡頓。對滾動驅動的動畫使用 GSAP ScrollTrigger 或 CSSanimation-timeline: scroll()。
品質檢查清單
- 所有動畫都使用
transform和opacity(合成友善的屬性) - 使用
useReducedMotion或 CSS 媒體查詢尊重prefers-reduced-motion - 微互動在 200ms 以下,頁面轉換在 400ms 以下
- 使用
AnimatePresence處理掛載/卸載動畫 - 佈局動畫使用 Framer Motion 的
layoutprop(非手動位置計算) -
will-change僅在動畫期間應用,完成後移除 - Chrome DevTools 效能面板中無卡頓(無超過 16ms 的長幀)
- 動畫可中斷(使用彈簧物理學,而非帶有
ease的固定關鍵影格) - View Transitions API 有針對不支援瀏覽器的後備方案
- 滾動驅動的動畫使用
animation-timeline或 ScrollTrigger(非滾動事件監聽器)