Framer Motion 완벽 가이드 | React 애니메이션·Variants
이 글의 핵심
Framer Motion으로 부드러운 애니메이션을 구현하는 완벽 가이드. Variants, Gesture, Layout Animation, Scroll까지 실전 예제로 정리. Framer Motion·Animation·React 중심으로 설명합니다.
이 글의 핵심
Framer Motion으로 부드러운 애니메이션을 구현하는 완벽 가이드입니다. Variants, Gesture, Layout Animation, Scroll까지 실전 예제로 정리했습니다.
실무 경험 공유: CSS 애니메이션을 Framer Motion으로 전환하면서, 코드가 60% 감소하고 애니메이션 품질이 크게 향상된 경험을 공유합니다.
들어가며: “애니메이션이 어려워요”
실무에서 마주치는 문제들
CSS 애니메이션이 복잡해요
keyframes는 번거롭습니다. Framer Motion은 간단합니다. 인터랙션이 부족해요
정적인 UI입니다. Framer Motion은 풍부한 인터랙션을 제공합니다. 성능이 걱정돼요
잘못된 애니메이션은 느립니다. Framer Motion은 최적화되어 있습니다.
1. Framer Motion이란?
핵심 특징
Framer Motion은 React 애니메이션 라이브러리입니다. 주요 장점
- 간단한 API: 선언적 문법
- Variants: 재사용 가능한 애니메이션
- Gesture: Drag, Hover, Tap
- Layout Animation: 자동 레이아웃 애니메이션
- 성능: GPU 가속
2. 설치 및 기본 사용
설치
npm install framer-motion
기본 애니메이션
import { motion } from 'framer-motion';
export default function Box() {
return (
<motion.div
initial={{ opacity: 0, y: 50 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.5 }}
>
Hello Framer Motion!
</motion.div>
);
}
3. Variants
기본 Variants
const variants = {
hidden: { opacity: 0, y: 50 },
visible: { opacity: 1, y: 0 },
};
export default function Box() {
return (
<motion.div
initial="hidden"
animate="visible"
variants={variants}
transition={{ duration: 0.5 }}
>
Content
</motion.div>
);
}
자식 애니메이션
const container = {
hidden: { opacity: 0 },
visible: {
opacity: 1,
transition: {
staggerChildren: 0.1,
},
},
};
const item = {
hidden: { opacity: 0, y: 20 },
visible: { opacity: 1, y: 0 },
};
export default function List() {
return (
<motion.ul variants={container} initial="hidden" animate="visible">
{items.map((item) => (
<motion.li key={item.id} variants={item}>
{item.name}
</motion.li>
))}
</motion.ul>
);
}
4. Gesture
Hover
<motion.button
whileHover={{ scale: 1.1 }}
whileTap={{ scale: 0.95 }}
>
Click me
</motion.button>
Drag
// 실행 예제
<motion.div
drag
dragConstraints={{ left: -100, right: 100, top: -100, bottom: 100 }}
dragElastic={0.2}
>
Drag me
</motion.div>
Tap
<motion.button
whileTap={{ scale: 0.9 }}
onTap={() => console.log('Tapped!')}
>
Tap me
</motion.button>
5. Layout Animation
자동 레이아웃
import { motion } from 'framer-motion';
import { useState } from 'react';
export default function ExpandableCard() {
const [isOpen, setIsOpen] = useState(false);
return (
<motion.div
layout
onClick={() => setIsOpen(!isOpen)}
style={{
padding: '1rem',
border: '1px solid #ccc',
borderRadius: '8px',
}}
>
<motion.h2 layout>Title</motion.h2>
{isOpen && (
<motion.p
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
>
Content goes here...
</motion.p>
)}
</motion.div>
);
}
AnimatePresence
import { AnimatePresence, motion } from 'framer-motion';
export default function List() {
const [items, setItems] = useState([1, 2, 3]);
return (
<ul>
<AnimatePresence>
{items.map((item) => (
<motion.li
key={item}
initial={{ opacity: 0, x: -50 }}
animate={{ opacity: 1, x: 0 }}
exit={{ opacity: 0, x: 50 }}
>
Item {item}
</motion.li>
))}
</AnimatePresence>
</ul>
);
}
6. Scroll Animation
useScroll
import { motion, useScroll, useTransform } from 'framer-motion';
export default function ScrollAnimation() {
const { scrollYProgress } = useScroll();
const opacity = useTransform(scrollYProgress, [0, 1], [1, 0]);
const scale = useTransform(scrollYProgress, [0, 1], [1, 0.5]);
return (
<motion.div style={{ opacity, scale }}>
Scroll to see animation
</motion.div>
);
}
useInView
import { motion, useInView } from 'framer-motion';
import { useRef } from 'react';
export default function FadeInWhenVisible() {
const ref = useRef(null);
const isInView = useInView(ref, { once: true });
return (
<motion.div
ref={ref}
initial={{ opacity: 0, y: 50 }}
animate={isInView ? { opacity: 1, y: 0 } : {}}
transition={{ duration: 0.5 }}
>
Fade in when visible
</motion.div>
);
}
7. 실전 예제
모달
import { motion, AnimatePresence } from 'framer-motion';
export default function Modal({ isOpen, onClose, children }) {
return (
<AnimatePresence>
{isOpen && (
<>
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
onClick={onClose}
style={{
position: 'fixed',
inset: 0,
background: 'rgba(0, 0, 0, 0.5)',
}}
/>
<motion.div
initial={{ opacity: 0, scale: 0.9 }}
animate={{ opacity: 1, scale: 1 }}
exit={{ opacity: 0, scale: 0.9 }}
style={{
position: 'fixed',
top: '50%',
left: '50%',
transform: 'translate(-50%, -50%)',
background: 'white',
padding: '2rem',
borderRadius: '8px',
}}
>
{children}
</motion.div>
</>
)}
</AnimatePresence>
);
}
정리 및 체크리스트
핵심 요약
- Framer Motion: React 애니메이션
- 간단한 API: 선언적 문법
- Variants: 재사용 가능
- Gesture: Drag, Hover, Tap
- Layout Animation: 자동
- Scroll: useScroll, useInView
구현 체크리스트
- Framer Motion 설치
- 기본 애니메이션 구현
- Variants 정의
- Gesture 추가
- Layout Animation 구현
- Scroll Animation 구현
- 성능 최적화
같이 보면 좋은 글
- shadcn/ui 완벽 가이드
- Tailwind CSS 완벽 가이드
- React 완벽 가이드
이 글에서 다루는 키워드
Framer Motion, Animation, React, UI, UX, Frontend, Performance
자주 묻는 질문 (FAQ)
Q. CSS 애니메이션과 비교하면 어떤가요?
A. Framer Motion이 훨씬 간단하고 강력합니다. CSS는 더 가볍지만 제한적입니다.
Q. 성능은 어떤가요?
A. 좋습니다. GPU 가속을 사용하고 최적화되어 있습니다.
Q. Next.js에서 사용할 수 있나요?
A. 네, 완벽하게 호환됩니다.
Q. 프로덕션에서 사용해도 되나요?
A. 네, Vercel, Stripe 등 많은 기업에서 사용합니다.