framer-motion은 리액트에서 애니메이션과 제스처를 쉽게 다룰 수 있게 해주는 라이브러리이다. initail, animate, exit prop에 값을 세팅하면 CSS transitions을 자동 생성하는 방법으로 애니메이션을 만들어준다.
메모 + 참고한 블로그
npm install framer-motion
import { motion } from 'framer-motion'
import { motion, useMotionValue, useMotionValueEvent, useTransform,
useScroll } from 'framer-motion'
//import해서 사용할 수 있는 기술이 여러개임
motion을 이용해서 HTML element 불러와야 한다.
<motion.div
animate={{
x: 0,
backgroundColor: "#000",
boxShadow: "10px 10px 0 rgba(0, 0, 0, 0.2)",
transitionEnd: {
display: "none",
},
}}
/>
<motion.div animate={{ scale: 2 }} />
const Box = styled(motion.div)`
width: 200px;
height: 200px;
background-color: rgba(255, 255, 255, 0.2);
border-radius: 10%;
`;
return (
<Box animate={{ borderRadius: "100px" }}/>
)
variantsconst boxVariants = {
start: {
opacity: 0,
scale: 0.5,
},
end: {
scale: 1,
opacity: 1,
transition: {
type: "spring",
duration: 0.5,
},
},
};
return (
<Box variants={boxVariants} initial="start" animate="end">
)
// 주려는 prop 이름을 적고 variants 내의 prop을 입력
// initial과 animate 말고도 whilehover 등이 있음..
Variants은 컴포넌트가 가질 수 있는 미리 정의된 시각적 state.
variants 객체를 만들어서 원하는 이름의 속성을 만들고 애니메이션 효과를 작성한다.
컴포넌트에 variants prop을 주고 앞서 만든 variants 전달,
원하는 애니메이션 prop 에 variants 객체 안의 프로퍼티 전달. (start, end)
ex) initial, animate, exit, whileHover ...
const boxVariants = {
start: {
opacity: 0,
scale: 0.5,
},
end: {
scale: 1,
opacity: 1,
},
};
return (
<Box variants={boxVariants} initial="start" animate="end" />
)
initail : 애니메이션 시작 명시, 초기 상태
animate : 애니메이션 최종 상태
exit : 애니메이션 종료
whileHover : 마우스 호버
whileTap : 마우스 누르는 동안
drag : 드래그가 가능하게 만듬
prop은 값을 객체로 받고 값이 지정되면 첫 렌더링시에, 또는 변경되면 변경된 값으로 motion 컴포넌트를 애니메이팅 한다.
scale : 크기 변화
rotate : x, y, z 회전
transition : 부드러운 변화 (색상, 크기, 위치)
type: 기본적으로 "spring". "tween" 으로 하면 선형적으로 바뀜 (linear)duration: 진행 속도 & delay: 지연 속도stiffness: 뻣뻣하게 만들어줌damping: 반동을 만들어줌. 0으로 하면 영원히 움직임.mass: 기본값 1. 질량. 무게감을 보여줌. 5로 하면 움직임이 무거워보임bounce: 0~1 사이의 값. 튕기는 정도. stiffness, damping, mass가 있다면 bounce와 duration 은 덮어씌워진다.<motion.div
animate={{
scale: [1, 2, 2, 1, 1],
rotate: [0, 0, 270, 270, 0],
borderRadius: ["20%", "20%", "50%", "50%", "20%"],
}}
/>
값을 array로 넣게 되면 순서대로 실행된다. 기본적으로는 동일한 시간으로 실행되나 transition 프로퍼티를 조정해서 시간값을 수정할 수 있다.
모션 컴포넌트 부모와 자식의 경우,
부모 모션 컴포넌트에 적용된 initail, animate 속성값은 자식들에게 자동적으로 동일하게 부여된다.return ( <Box variants={boxVariants} initial="start" animate="end"> <Circle initial="start" animate="end" /> <Circle /> // 자동적으로 위 Circle처럼 되어있다. </Box> )
Orchestration:
자식요소에 애니메이션 효과 주기. (transition 옵션)
delayChildren: 모든 자식들에게 딜레이 시간(초) 후에 하위 애니메이션이 시작.
staggerChildren: 하위 컴포넌트의 애니메이션에 시차를 둘 수 있음.
예를 들어,staggerChildren이 0.01이면 첫 번째 자식은 0초, 두 번째 자식은 0.01초, 세 번째 자식은 0.02초 지연되는 식. 계산된 stagger 딜레이가 delayChildren에 추가.
inherit: boolean : 부모로부터 variants 변경 사항을 상속하지 않도록 하려면 false로 설정.
const Box = styled(motion.div)`
display: grid;
grid-template-columns: 1fr 1fr;
width: 200px;
height: 200px;
background-color: rgba(255, 255, 255, 0.2);
border-radius: 20%;
box-shadow: 0 2px 3px rgba(0, 0, 0, 0.1), 0 10px 20px rgba(0, 0, 0, 0.06);
`;
const Circle = styled(motion.div)`
place-self: center; //justify-self와 align-self를 합친 축약
background-color: white;
width: 70px;
height: 70px;
border-radius: 50%;
box-shadow: 0 2px 3px rgba(0, 0, 0, 0.1), 0 10px 20px rgba(0, 0, 0, 0.06);
`;
const boxVariants = {
start: {
opacity: 0,
scale: 0.5,
},
end: {
scale: 1,
opacity: 1,
transition: {
type: "spring",
duration: 0.5,
bounce: 0.5,
delayChildren: 1, // 자식 요소 모두 1초 딜레이
staggerChildren: 0.3, //자식 요소에 순차적으로 0.3초 딜레이
},
},
};
const circleVariants = {
start: { opacity: 0, y: 20 },
end: { opacity: 1, y: 0, transition: { duration: 1 } },
// x와 y는 css가 아닌 motion 좌표 수정 기능.
// y에 값을 줘서 살짝 올라오며 생성되도록 보이게 함.
};
function Animation() {
return (
<Box variants={boxVariants} initial="start" animate="end">
<Circle variants={circleVariants} />
<Circle variants={circleVariants} />
<Circle variants={circleVariants} />
<Circle variants={circleVariants} />
// boxVarinats와 프로퍼티 이름을 동일하게 만들어서 initial="start"~ 생략 가능
</Box>
}
whileTap: 마우스로 누르는 동안.
drag: 드래그 가능하게 됨. 추가로 x, y값을 줘서 드래그 방향을 결정할 수 있음
whileDrag: 드래그 하는 동안. 추가로 backgroundColor를 rgba값 준다면 색상 변화도 애니메이트
dragElastic: 기본값 0.5 이다. 1로 하면 마우스 커서와 드래그하는 것과 똑같이 움직임
dragSnapToOrigin: 드래그가 끝나면 제자리로.
dragConstraints: 드래그가 되는 공간을 제한.
ex) dragConstraints={{top: -100}} 또는 useRef로 바깥 박스를 잡아서 값으로 주기
const biggerBoxRef = useRef<HTMLDivElement>(null); : ts 사용시
const biggerBoxRef = useRef(null);
return <Box dragConstraints={biggerBoxRef} />
const BiggerBox = styled.div`
display: flex;
justify-content: center;
align-items: center;
flex-wrap: wrap;
width: 800px;
height: 800px;
background-color: rgba(255, 255, 255, 0.2);
border-radius: 20%;
`;
const boxVariants = {
hover: { scale: 1.5, rotateZ: 90 },
//Box 컴포넌트에 prop을 whileHover로
click: { scale: 1, borderRadius: "100px" },
//Box 컴포넌트에 prop을 whileTap으로
};
//variansts 내의 이름은 아무렇게 지어도 상관없지만
//motion prop과 이름을 같게 만들면 축약으로 사용할 수 있음.
export default function Animation() {
const biggerBoxRef = useRef(null);
//드래그 영역으로 biggerBox 만큼 제한하려고 useRef 사용
return (
<BiggerBox ref={biggerBoxRef}> // ref
<Box variants={boxVariants} whileHover="hover" whileTap="click" />
//variants 로 애니메이션 적용
<Box whileHover={{ scale: 1.2, rotateZ: 90 }} whileTap={{ scale: 1, borderRadius: "100px" }} />
// prop 직접 입력
<Box drag dragConstraints={biggerBoxRef} whileDrag={{ backgroundColor: "rgba(255, 255, 255, 0.3)" }} />
// biggerBox 영역만큼 드래그 가능. 드래그 하는 동안 색상 변화
</BiggerBox>
);
}