Framer Motion을 오랜만에 쓸 때 보는 간단한 포스트

Ellie·2022년 5월 20일
7

Framer Motion

0/7. 설치

npm i framer-motion


1/7. 컴포넌트에서 framer motion 불러오기

그 후 framer motion을 사용할 컴포넌트에서
import { motion } from "framer-motion"
으로 불러온다.

import { motion } from "framer-motion"

function App () {
  return (
    <main>
    // motion으로부터 HTML element를 불러온다.
      <motion.div></motion.div>
    </main>
  )
}

export default App;

2/7. Basic Animation & Transition

Animation

: 요소의 모든 움직임 정의
Framer Motion Doc: Animation

  • animate 속성을 통해 제어된다.

Transition

: 한 상태에서 다른 상태로 움직이는 방식 정의
Framer Motion Doc: Transition

  • transition 속성을 통해 제어된다.
  • props로는 type의 Tween, Spring, Inertia가 있다.
  • 또한 stiffnessdamping, bounce, mass등이 있다.
function App () {
  return (
    <main>
    // motion으로 된 styled-component
      <Box 
        // element의 초기상태 지정
        initial={{ scale: 0 }}
  		animate={{ scale: 1, rotateZ: 360 }}
        transition={{ type= "spring", damping: 10 }}
      />
    </main>
  )
}

const Box = styled(motion.div)`
	width: 200px;
	height: 200px;
`;

export default App;

3/7. Variants

: 애니메이션 객체를 생성하고, 자식 요소의 애니메이션도 제어할 때
Framer Motion Doc: Introduction/##variants
Variants는 애니메이션 객체를 생성하여 코드를 깔끔하게 만들어줄 뿐만 아니라 부모 요소에 Variants를 등록했을 때 안의 자식 요소들에게까지 그 Variants을 전달한다. 똑같이 등록할 필요가 읎음!

variants 대표 기능

  • 애니메이션 객체 생성
  • Orchestration 로 자식 컴포넌트 애니메이션까지 제어 가능
    • delayChildren
    • staggerChildren
    • staggerDirection
    • when
// variants객체 생성
const boxVars = { // 부모의 variants 객체
  start: { 
    opacity: 0,
    scale: 0.5,
  },
  end: { 
    opacity: 1,
    scale: 1, 
    rotateZ: 360, 
    transition: { 
      type= "spring", 
      duration: 0.5,
      bounce: 0.5, 
      delayChildren: 0.5,  // 자식 컴포넌트는 0.5초 느리게 나타나게 하는 속성
	  staggerChildren: 0.2, //  자식 컴포넌트 하나 나타나고 그다음 컴포넌트에 0.2초 딜레이 부여
    }
  }
}

const circleVars = { // 자식의 variants 객체
  start: {
  	opacity: 0,
    y: 10
  },
  end: {
    opacity: 1,
    y: 0,
  },
}

function App () {
  return (
    <main>
      <Box
    	variants={boxVars} // 부모 variants 등록
		initial="start" // boxVars 객체에 있는 키값과 동일하게 작성해야함
		animate="end"
      >
          // 부모 컴포넌트 Box 객체 키값을 상속받음! 
          // 자식은 부모의 initial="start" animate="end"를 상속받는다고 생각하면 된다. 
          // 그래서 자식 variants를 생성할 때 키값을 동일하게 작성해주는 것이 중요하다!
          <circle variants={circleVars} >
          <circle variants={circleVars} >
          <circle variants={circleVars} >
          <circle variants={circleVars} >
      </Box>
    </main>
  )
}

framer motion 속성들을 하나의 객체로 만들어줌으로써 컴포넌트가 좀 더 깔끔해졌다.


4/7. Gestures

: drag, hover, tap, pan, viewport를 감지해 애니메이션 지원. 마우스 상태에 따른 몇몇 이벤트 리스닝 제공. 사용자의 움직임과 상호작용하고 싶다면 Gestures 을 사용하면 된다.
Framer Motion Doc: Gestures

  • Gesture animation props
    • whileHover
      : 커서가 컴포넌트 위로 이동하거나 떠날 때 동안의 애니메이션 속성.
    • whileTap
      : 컴포넌트를 클릭하고 있는 동안의 애니메이션 속성
    • whileFocus
      : 컴포넌트를 클릭해 포커스된 동안의 애니메이션 속성
    • whileDrag
      : 끌기 제스쳐가 발생하는 동안의 애니메이션 속성
    • whileInView
      : 보통 스크롤 할 때 사용, 내리면서 컴포넌트가 뷰포트에 있는 동안의 애니메이션 속성
const boxVars = { 
  hover: { scale: 2 rotateZ: 90 },
  click: { scale: 1 borderRadius: "50px" },
  drag: { backgroundColor: "rgb(165, 102, 255) },
  transition
}

function App () {
  const ParentsBoxRef = useRef<HTMLDivElement>(null);
  
  return (
    <main>
      <ParentsBox ref={ParentsBoxRef}>
        <Box
          variants={boxVars} 
          whileHover="hover" // 커서를 올려놓는 동안
          whileTap="click" // 클릭하는 동안
          drag // 끌기 등록
          // drag="x" 는 x축으로만 움직일 수 있도록 제한. 
          // y는 y축으로만.
          dragConstraints={ParentsBoxRef} // 끌기 영역 제한 설정
	      dragElasic={0.3} // 0 ~ 1 사이 값, 제한 영역 밖으로 나가도 보이긴 함.
 		  dragSnapToOrigin // 아무리 멀리 끌어도 제자리로 돌아감, 제한 영역 밖으로 나가면 안 보임
          whileDrag="drag" // 끄는 동안의 애니메이션
        />
      </ParentsBox>
    </main>
  )
}

5/7. MotionValues

애니메이션 값의 상태와 속도를 추적한다. 그렇지만 React State가 아니기 때문에 모션값의 상태가 바뀌어도 리렌더링 되지 않는다. 위치에 따라 애니메이션을 다르게 설정할 수 있다.
Framer Motion Doc: MotionValue

  • useMotionValue()
    :MotionValue를 얻어올 변수 정의, 모션 컴포넌트의 style 속성에 연결
  • useTransform()
    :MotionValue값에 따라 다른 애니메이션을 도출하고 싶을 때 사용하는 훅
const x = useMotionValue(0) // x축 값
const input = [-200, 0, 200] // x축 범위 인풋
const output = [2, 1, 2] // scale 범위 아웃풋
const scale = useTransform(x, input, output)
  • useViewportScroll()
    • scrollX
      : 실제 수평 스크롤 픽셀 ex) 500px
    • scrollY
      : 실제 수직 스크롤 픽셀 ex) 500px
    • scrollXProgress
      : 0 ~ 1 사이의 수평 스크롤
    • scrollYProgress
      : 0 ~ 1 사이의 수직 스크롤(가장 상단 0, 가장 하단 1)
  • get()
  • set()
  • onChange()

useMotionValue 코드 예시

import {motion, useMotionValue, useTransform} from "framer-motion";

export function MyComponent() {
  const x = useMotionValue(0) // default = 0
  const scale = useTransform(x, [-200, 0, 200], [2, 1, 2]);
  const gradient = useTransform(
    x, 
    [-200, 200], 
    [
      "linear-gradient(135deg, rgb(0, 210, 238), rgb(0, 83, 238))",
      "linear-gradient(135deg, rgb(0, 238, 155), rgb(238, 178, 0))",
    ]
  )
  
  return (
    // useMotionValue()
  	<motion.div style={{ backgroundColor: gradient }}>
      // x.set()로 값을 업데이트해 해당 컴포넌트의 위치를 조작할 수 있다. get()과 onChange()도 있음.
      <button onClick={() => x.set(200)}>click me</button>
	  <motion.div style={{ x, scale }} drag="x" />
    </motion.div>
  )
}

useViewportScroll 코드 예시

import {motion, useTransform, useViewportScroll} from "framer-motion";

function App () {
  const { scrollYProgress } = useViewportScroll();
  const scale = useTransform(scrollYProgress, [0, 1], [1, 3]);
  
  return (
    <motion.div>
      <motion.div style={{ scale }}>
    </motion.div>
  )
}

6/7. SVG Animation

svg의 속성들을 이용하여 다양한 애니메이션을 만들어낼 수 있다.
SVG 속성

  • width
    : 도형의 너비
  • height
    : 도형의 높이
  • stroke
    : 도형의 테두리 색상
  • stroke-width
    : 도형의 테두리 굵기
  • fill
    : 도형을 채울 색상
  • opacity
    : 도형의 투명도
const svg = {
  start: {
    fill: "rgba(255,255,255,0)",
    pathLength: 0, // 선이 그려지는 정도 0 ~ 1
    stroke: "white", // 선
    strokeWidth: 2, // 선 굵기
    d: "...(코드중략)",
  },
  end: {
    fill: "rgba(255,255,255,1)",
    pathLength: 1,
    transition: {
      // 특정 property만 더 나중으로 딜레이되도록 만들기
      default: { duration: 5 }, // 모든 요소는 5초 동안
      fill: { duration: 2, delay: 3 }, // fill요소는 5초 후 2초 동안 
    },
  },
};

function App () {
  return (
    // 부모 요소인 svg는 motion element가 아니어도 되지만 그 안의 자식요소인 path는 motion element여야 한다.
    <svg>
      <motion.path
    	variants={svg}
		initial="start"
		animate="end"
      >
      </motion.path>
	</svg>
  )
}

기억할만한 것은 transition 부분에서 어떤 특정 속성만 애니메이션 값을 다르게 주고 싶을 때

transition: {
	default: { 모든 요소에 적용 }, 
    특정속성명: { 특정 요소에만 적용}
}

이렇게 적어주면 된다는 것이다.


7/7. Animate Presence

AnimatePresence는 React App에서 사라지는 컴포넌트에 애니메이션 효과를 줄 수 있다. React 자체에서는 컴포넌트가 사라지면 그냥 끝이라서 라이프사이클로 어떤 효과도 줄 수 없지만 motion에서는 사라지는 컴포넌트에 애니메이션 효과를 줄 수 있다.
Framer Motion Doc: animate-presence

  • exit
    : 이 property가 있는 컴포넌트가 바로 애니메이션 대상이다.
import {motion, AnimatePresence} from "framer-motion";

function App = ({ isVisible }) => (
  // AnimatePresence로 감싸준다.
  <AnimatePresence>
    {isVisible && (
      initial={{ opacity: 0 }}
      animate={{ opacity: 1 }}
      exit={{ opacity: 0 }} // 이 속성으로 사라질 때의 애니메이션 효과를 줄 수 있다.
    />
    )}
  </AnimatePresence>
)

마무리

framer-motion은 Variants, Gesture, MotionValues 등 개념만 알고 나면 정말 쉽게 애니메이션 도움을 받을 수 있는 라이브러리다. 정말 다양한 효과를 줄 수 있어서 화려한 효과가 필요한 UI에 자주 애용할 것 같다.

특히 컴포넌트가 사라질 때 줄 수 있는 애니메이션 효과라니!👍 또 자식 컴포넌트들이 부모의 애니메이션을 상속받는 것이나 자식들이 순서대로 효과를 나타내는 staggerChildren 등 유용한 기능이 짱 많당.

지금 이 포스트에서 framer-motion들의 개념을 포함의 일부 기능만 작성했다. 모든 걸 작성하기에는 스크롤의 압박이 심해져서 다음 포스트에 작성해보려고 한다
👏👏

그럼 20000!

profile
정말로 아는 것인지 항상 의심하기

0개의 댓글