stack-analysis
CHAPTER 24 / 90
읽기 약 2분
FUNCTION
애니메이션 + Framer Motion: 부드러운 UX
핵심 개념
CSS transition·Framer Motion·layout animation·gesture — 60fps 보장.
본문
CSS 우선 — 가벼움
/* transform + opacity만 60fps 안정 */
.card {
transition: transform 0.2s ease, box-shadow 0.2s ease;
}
.card:hover {
transform: translateY(-4px) scale(1.02);
box-shadow: 0 10px 30px rgba(0,0,0,0.15);
}
/* will-change — GPU 힌트 (남발 금지) */
.animated-element {
will-change: transform;
}Framer Motion 기본
import { motion } from 'framer-motion';
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0, y: -20 }}
transition={{ duration: 0.3, ease: [0.22, 1, 0.36, 1] }}
>
{content}
</motion.div>페이지 전환 (AnimatePresence)
'use client';
import { AnimatePresence, motion } from 'framer-motion';
import { usePathname } from 'next/navigation';
export function PageTransition({ children }: { children: React.ReactNode }) {
const pathname = usePathname();
return (
<AnimatePresence mode="wait">
<motion.div
key={pathname}
initial={{ opacity: 0, x: 20 }}
animate={{ opacity: 1, x: 0 }}
exit={{ opacity: 0, x: -20 }}
transition={{ duration: 0.3 }}
>
{children}
</motion.div>
</AnimatePresence>
);
}스태거 애니메이션 (목록)
const container = {
hidden: { opacity: 0 },
show: {
opacity: 1,
transition: { staggerChildren: 0.1, delayChildren: 0.2 },
},
};
const item = {
hidden: { opacity: 0, y: 20 },
show: { opacity: 1, y: 0 },
};
<motion.ul variants={container} initial="hidden" animate="show">
{items.map(i => (
<motion.li key={i.id} variants={item}>{i.name}</motion.li>
))}
</motion.ul>Layout Animation (FLIP)
// 자동 위치/크기 전환 — FLIP 알고리즘
<motion.div layout>
{expanded ? <FullContent /> : <Summary />}
</motion.div>
// 공유 요소 전환
{items.map(item => (
<motion.div
key={item.id}
layoutId={`card-${item.id}`}
onClick={() => setSelected(item)}
>
{item.title}
</motion.div>
))}
{selected && (
<motion.div layoutId={`card-${selected.id}`}>
{/* 클릭한 카드가 자연스럽게 확대 */}
<FullView item={selected} />
</motion.div>
)}제스처 (drag, swipe)
<motion.div
drag
dragConstraints={{ left: -100, right: 100, top: 0, bottom: 0 }}
dragElastic={0.5}
whileDrag={{ scale: 1.05, cursor: 'grabbing' }}
>
드래그 가능
</motion.div>
// 스와이프 (예: Tinder)
<motion.div
drag="x"
onDragEnd={(_, info) => {
if (info.offset.x > 100) onSwipeRight();
if (info.offset.x < -100) onSwipeLeft();
}}
>
...
</motion.div>60fps 체크리스트
✅ transform + opacity만 (layout/paint 트리거 X)
✅ DevTools > Performance > FPS 측정
✅ 큰 영역에 will-change: transform 명시
✅ 60fps 목표 — 16.67ms/frame
✅ requestAnimationFrame 또는 라이브러리 사용
✅ 모바일에서 reduce motion 지원prefers-reduced-motion
@media (prefers-reduced-motion: reduce) {
* {
animation-duration: 0.01ms !important;
transition-duration: 0.01ms !important;
}
}다음 챕터
CH.25 "접근성(a11y)" — WCAG 2.2 + ARIA.
AI 프롬프트
🤖 AI에게 잘 물어보는 법 — 모델·전략별 프롬프트
Claude
무료: Sonnet 4.6 / Pro $20/mo: Opus 4.6
내 코드의 애니메이션 부분을 분석해서 실전 분석 + 개선 우선순위를 알려줘.
ChatGPT
무료: GPT-5.5 / Plus $20/mo: GPT-5.5 Pro
애니메이션 관련 인기 라이브러리/패턴 5개를 비교 분석해서 패턴 추출를 알려줘.
Gemini
무료: 2.5 Flash / Pro $19.99/mo: 3.1 Pro
내 프로젝트 전체에서 애니메이션 최적화 가능 위치를 보고해줘.
Grok
무료: Grok 4.1 / SuperGrok $30/mo
2026년 한국 프론트엔드 시장의 애니메이션 트렌드를 솔직히 알려줘.
⭐ 이것만 기억하세요
애니메이션 + Framer Motion: 부드러운 UX는 이 3가지만 확실히 잡으세요
1.transform + opacity = GPU 가속 60fps — 다른 속성은 layout 비용
2.Framer Motion AnimatePresence + layout = 페이지/요소 전환 표준
3.prefers-reduced-motion 지원 = 접근성 의무
공유하기
진행도 24 / 90