본문으로 건너뛰기 Framer Motion 완벽 가이드 | React 애니메이션·Variants

Framer Motion 완벽 가이드 | React 애니메이션·Variants

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 구현
  • 성능 최적화

같이 보면 좋은 글


이 글에서 다루는 키워드

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 등 많은 기업에서 사용합니다.