Motion Animation
2024.11.20
단순히 CSS만으로는 간단한 애니메이션을 구현할때에도 매우 많은 코드를 작성해야 됩니다.
motion (구 framer-motion)
는 간단한 코드들로 빠르게 애니메이션 효과를 구현할 수 있습니다.
탭 애니메이션
motion에서는 layoutId를 사용하여 깉은 요소들을 연결시켜서 자연스러운 레이아웃을 제공합니다.
활성 컴포넌트를 표시하는 motion.span
에 layoutId
를 설정하여 각 탭 item들을 연결시킨 뒤 transition={{ type: "spring", bounce: 0.2, duration: 0.6 }}
애니메이션 효과를 적용하여 부드럽게 전환되는 애니메이션을 구현할 수 있습니다.
모핑 카드
Native App에서는 위와같은 모핑 카드가 많이 사용됩니다. 모핑 카드를 사용하면 부드러운 애니메이션을 통해 사용자에게 더 나은 경험을 제공할 수 있습니다.
탭 애니메이션과 같이 layoutId
를 사용하여 이미지와 텍스트를 연결시킵니다.
카드가 클릭되어 선택 상태로 변경될 때, motion.div의 layoutId를 활용하여 카드의 크기와 위치 변화에 애니메이션을 추가하고, transition={{ layout: { duration: 0.4, ease: "easeInOut" }}}
로 애니메이션의 지속 시간과 속도 변화를 설정해줍니다.
텍스트부분의 경우, 카드가 확장된 후에 AnimatePresence를 initial={{ opacity: 0 }}
로 초기 상태를 설정하고, animate={{ opacity: 1 }}
로 애니메이션을 적용했습니다.
드래그 앤 드롭
DnD기능은 여러 라이브러리로 구현할 수 있지만, motion을 사용하여 커스텀하기 쉽게 구현할 수 있습니다.
<Reorder.Group axis="y" onReorder={setItems} values={items}>
{items.map((item) => (
<Reorder.Item key={item} value={item}>
{item}
</Reorder.Item>
))}
</Reorder.Group>
motion에서는 <Reorder.Group />
으로
<Reorder.Item />
을 감싸서 각 아이템들을 DnD기능을 구현할 수 있습니다.
axis="y"
로 드래그 방향을 설정하고, onReorder
로 해당 아이템의 변경될때의 상태를 관리할 수 있습니다.
const Item = ({ item }: ItemProps) => {
const y = useMotionValue(0);
const dragControls = useDragControls();
return (
<Reorder.Item value={item} style={{ y }} dragControls={dragControls}>
<div
drag
dragControls={dragControls}
onPointerDown={(event) => dragControls.start(event)}
>
<span>{item}</span>
</div>
</Reorder.Item>
);
};
useDragControls
훅으로 각 아이템을 제어 할 수 있습니다.
drag
속성을 추가하여 해당 요소를 드래그할 수 있도록 설정하고, onPointerDown
이벤트로 드래그를 시작하도록 설정합니다.
useMotionValue
훅으로 y값을 설정하여 드래그시에 y값을 변경하도록 설정합니다.
오버레이 컴포넌트
다음 컴포넌트는 간단한 서랍장 컴포넌트입니다.
motion
을 사용하면 다양한 overlay 컴포넌트를 쉽게 구현할 수 있습니다.
버튼을 클릭할때 isOpen
상태를 변경하여 AnimatePresence
안의 motion.div
의 initial
과 animate
를 사용하여 애니메이션을 적용하였습니다.
위와 같이 간단한 오버레이 컴포넌트를 만들때 다양한 효과를 넣어서 좀더 사용자에게 나은 경험을 제공할 수 있습니다.
이와 같이 여러 효과를 CSS 코드로 넣으면 다음과 같이 많은 작성해야하며, 각 HTML 요소에 상태별로 클래스를 추가해야합니다.
.drawer-enter {
opacity: 0;
transform: scale(0.9) translateY(50px) translateX(-50%);
}
.drawer-enter-active {
opacity: 1;
transform: scale(1) translateY(0) translateX(-50%);
transition: opacity 0.2s ease-out, transform 0.2s ease-out;
}
.drawer-exit {
opacity: 1;
transform: scale(1) translateY(0) translateX(-50%);
}
.drawer-exit-active {
opacity: 0;
transform: scale(0.9) translateY(50px) translateX(-50%);
transition: opacity 0.2s ease-out, transform 0.2s ease-out;
}
이는 매우 번거롭고, 유지보수가 어렵습니다. 아래와 같이 motion을 사용하면 간단한 코드로 애니메이션을 구현할 수 있습니다.
<motion.div
initial={{ opacity: 0, scale: 0.9, y: 50, x: "-50%" }}
animate={{ opacity: 1, scale: 1, y: 0, x: "-50%" }}
exit={{ opacity: 0, scale: 0.9, y: 50, x: "-50%" }}
transition={{ duration: 0.2, ease: "easeOut" }}
/>