Framer Motion 기초

Visual UI
2026.06.10
Framer Motion 기초

React 기반 애니메이션 라이브러리

Framer Componenet

  • 모든 HTML 및 SVG 요소
  • <motion.div> <motion.span> <motion.circle>

애니메이션 구조

  • 애니메이션 초기 상태 (마운트 시점)
  • 애니메이션 끝난 상태
  • 애니메이션 진행 모습

Props

Animation

  • initial 애니메이션 초기 상태 (마운트 시점)
  • animate 애니메이션 끝난 상태
  • transition 애니메이션 진행 모습 (linear, easeInOut, circInOut …)
<motion.div
	className="w-20 h-20 bg-amber-100"
	initial={{ x: 40, y: 40, rotate: 45 }}
	animate={{ x: 60, y: 60, rotate: 0 }}
	transition={{ ease: 'circInOut', duration: 1 }}
/>
  • exit 트리에서 제거될 때 상태
    • <AnimatePresence> 의 직계 자식이어야만 애니메이션 활성화
<AnimatePresence>
	{isVisible &&(
		<motion.div
			...
			exit={{ opacity:0 }}
		/>
	)}
</AnimatePresence>

Hover, Tap(click/touch)

  • whileHover
  • onHoverStart onHoverEnd 마우스 오버 콜백 함수
  • whileTab click/touch
  • onTapStart onTap onTapCancel Tap 콜백 함수

Pan

제스처 인식될 때 콜백 함수
터치 디바이스 환경에서 사용 시 터치 비활성화 touch-action:none

  • onPan onPanStart onPanEnd
<motion.div onPan={(event, info)=> info.point.x} />
  • point 페이지 기준 좌표
  • delta 마지막 이벤트 후 거리
  • offset 이벤트 발생 지점과의 거리
  • velocity 포인터 속도

변수

  • 인라인 정의 시 읽기 어렵고 복잡함 → 변수로 정의
  • 동적으로 사용 가능
const AniButton = () => {
	const [isClicked, setIsClicked] = useState(false);

	const buttonVariants = {
		reset: {
			scale: 1,
		},
		hover: (isClicked)=> ({ // 동적 사용
			scale: isClicked ? 1 : 1.5,
		}),
		pressed: {
			scales: 0.5,
		},
	}

	return(
		<motion.button
			initial="reset"
			whileHover="hover"
			whileTab="pressed"
			variants={buttonVariants}
			custom={isClicked}
			onClick{() => setIsClicked(true)}
		>
			Click
		</motion.button>
	)
}

Motion Values

애니메이션 상태와 속도 추적

  • MotionValue 생성 후 inline 스타일에 정의
  • .get() .set() 매서드로 값 관리
  • useMotionValue MotionValue 정의 (style 속성명과 일치시키는게 관례)

useTransform 다른 MotionValue로 변환, 맵핑

  • useTransform(감지할 속성, 범위 맵핑, 변환 값)
const stylePropA = useMotionValue(0)
const stylePropB = useTransform(x, input, output)
// 감지할 stylePropA, [stylePropA 상태 값], [stylePropA 맵핑 후 stylePropB 변환 값]
const aniBox = {
	initial: {
		scale: 0,
	},
	animate: {
		scale: 1
	},
};

const scale = useMotionValue(0);
const rotate = useTransform(scale, [0.9, 1], [0, 90])
return(
	<motion.div
		style={{ scale, rotate }}
		variants={aniBox}
		initial="initial"
		animate="animate"
		transition={{ ease: "circInOut", duration: 2 }}
	>
	</motion.div>
)
  • useMotionValueEvent(motionValue, 이벤트, 콜백)
    • 이벤트 : change animationStart animationComplete animationCancel

useSpring 최종 목표값으로 이동시 스프링 애니메이션

const scale = useSpring(scale, { stiffness: 200, damping: 10 })
  • stiffness : 목표에 도달하는 속도
  • damping : spring 효과 (낮을수록 효과 증가)
  • Raw 데이터를 실시간으로 필터링 (사용예시 마우스 포인터 추적, 스크롤 진척도 연동)

Delay

const aniParent = {
	animate:{
		...
		transition:{
			duration:0.5,
			delayChildren: 2, // Children element animation 딜레이
			staggerChildren: 0.2, // 딜레이 후 다음 형제 element 딜레이
		}
	}
}
return (
	<motion.div
		variants={aniParent}
		...
		animate="animate"
	>
		<motion.span />
		<motion.span />
		<motion.span />
	</motion.div>
)

Drag

  • dragConstraints 드래그 영역 제약
<motion.div drag dragConstraints={{ left:0, right:0}} />
const MyComponent = () => {
  const constraintsRef = useRef(null)

  return (
     <motion.div ref={constraintsRef}> // ref 로 지정
         <motion.div drag dragConstraints={constraintsRef} />
     </motion.div>
  )
}
  • dragSnapToOrigin 원상태로 돌아가기
  • dragElastic 드래그 영역 밖 움직임 정도 (default: 0.5)

바닐라 JavaScript 환경

<script src="https://cdn.jsdelivr.net/npm/motion@latest/dist/motion.js"></script>
<script>
  const { animate, scroll } = Motion
</script>
animate("선택자", {애니메이션})

Modal 팝업 구현

const modal = document.querySelector('#myModal')
if(isOpen){
	animate(
		modal,
		{
			y: [80, 0],
			opacity: [0, 1],
			scale: [0.8, 1],
		},
		{ duration: 1, ease: 'circInOut' },
	)
} else {
	const animation = animate(
		modal,
		{
			y: 80,
			opacity: 0,
			scale: 0.8,
		},
		{ duration: 1, ease: 'circInOut' },
	)
	await animation.finished
	if (!isOpen) {
		modal.style.display = 'none'
	}
}

Framer Motion 튜토리얼
Framer Motion Docs

© 2026 Choi Seohee. All Rights Reserved.