#7 ANIMATIONS

#7.1

Examples | Framer for Developers

Framer Motion

React용 production-ready 모션 라이브러리 (오픈 소스)

https://www.framer.com/motion

https://github.com/framer/motion

npm i framer-motion

import { motion } from "framer-motion”

motion 사용시 기존의 <div> 은 사용할 수 없음

<motion.div> 로 사용해야함

CRACO

CRACO(Create React App Configuration Override)는 create-react-app을 위한 쉽고 이해하기 쉬운 configuration 레이어입니다. 애플리케이션 root에 단일 configuration(예: craco.config.js) 파일을 추가하고 eslint, babel, postcss configuration 등을 사용자 지정하여 'eject'를 사용하지 않고 create-react-app 및 사용자 지정의 모든 이점을 얻으십시오.

https://github.com/gsoft-inc/craco

https://github.com/gsoft-inc/craco/blob/master/packages/craco/README.md#installation

craco.config.js


module.exports = {

webpack: {

configure: {

module: {

rules: [

{

type: 'javascript/auto',

test: /\\.mjs$/,

include: /node_modules/,

},

],

},

},

},

}

#7.2 Animation

Framer Motion의 애니메이션은 모션 컴포넌트의 유연한 animate 속성을 통해 제어된다.

간단한 애니메이션은 animate props에서 직접 값을 설정할 수 있다.

initial - 시작 / transition - 변화 방법 / animate - 종료

#7.3 Variants part

Variants 여러 애니메이션을 합칠 수 있음 & 깔끔한 코드

const variant = {
    start: {},
    end: {}
}

motion.div variant={variant} initial=“start” end=”end”

#7.4

부모 요소의 애니메이션과 props를 자식 요소에도 전달한다.

& 각 자식 요소에 각각 딜레이 주는 등의 미친 기능도 가능하다.

delayChildren: 딜레이 시간(초) 후 하위 애니메이션 시작

staggerChildren: 하위 컴포넌트의 애니메이션에 지속 시간(초)만큼 시차 예를 들어, staggerChildren이 0.01이면 첫 번째 자식은 0초, 두 번째 자식은 0.01초, 세 번째 자식은 0.02초 지연. 계산된 stagger 딜레이가 delayChildren에 추가된다.

inherit: boolean

부모로부터 variant 변경 사항을 상속하지 않도록 하려면 false로 설정.

#7.5 Gestures

whileHover - 호버 중일때 작동할 애니메이션

whileTap - 클릭 중일때 작동할 애니메이션

Drag

drag: boolean | “x” | “y”

끌기 활성화- 기본 false 양방향 드래그를 원하면 true, 특정 방향으로 하려면 x or y 설정

whileDrag - 드래그 중일때 작동할 애니메이션

dragConstraints - 드래그가 허용되는 범위 (1. 픽셀 크기 이용 2. ref 이용)

dragSnapToOrigin - 원래 자리로 돌아감

dragElastic - 외부 제약 조건에서 허용되는 이동 정도 0=움직임 없음 1=전체 움직임 기본 0.5 false가능

#7.7 MotionValues

특정 값을 추적하지만 state가 아니다?!

.set() .get() 메서드로 값을 업데이트하거나 지정할 수 있다.

#7.8 useTransform

특정값을 다른 값으로 변환해준다.

useTransform(x, input, output) ⇒ x의 값을 input 범위에서 output 범위로 변환한다.

#7.9 useScroll

뷰포트가 스크롤 될 때 업데이트되는 MotionValues 값을 리턴한다.

scrollX - 실제 수평 스크롤 픽셀

scrollY - 실제 수직 스크롤 픽셀

scrollXProgress - 0~1 사이의 수평 스크롤

scrollYProgress - 0~1 사이의 수직 스크롤

이 값을 이용해 스크롤 위치에 따라 애니메이션을 추가할 수 있음 !!


#7.a package.json 한번에 업데이트하기

npm-check-updates 사용

npm install -g npm-check-updates // 패키지 설치

ncu -u // 업데이트 가능한 항목 확인

npm install // 업데이트

#7.10 SVG Animation

fontAwsome 에서 svg 파일 가져오기

path(SVG) ⇒ 모양을 정의하는 엘리먼트

transition 각각 줄 수 있음 ㅁㅊㄷ !

Line drawing

svg 엘리먼트에 'pathLength', 'pathSpacing', 'pathOffset' 속성을 사용하여 Line drawing 애니메이션을 만들 수 있습니다.

https://www.framer.com/docs/examples/#line-drawing

path (SVG)

path SVG 엘리먼트는 모양을 정의하는 일반 엘리먼트입니다.모든 기본 모양은 path 엘리먼트로 만들 수 있습니다.

path의 속성 d는 경로의 모양을 정의합니다.

https://developer.mozilla.org/en-US/docs/Web/SVG/Element/path

Path

motion.path 컴포넌트는 세 가지 강력한 SVG path 속성인 pathLength, pathSpacing 및 pathOffset을 가지고 있습니다. 수동 경로 측정이 필요 없이 모두 0과 1 사이의 값으로 설정됩니다.

Line drawing

선 그리기 애니메이션은 pathLength, pathSpacing 및 pathOffset의 세 가지 특수 속성을 사용하여 많은 SVG 요소로 만들 수 있습니다.

ex) motion.circle initial={{ pathLength: 0 }} animate={{ pathLength: 1 }}

https://www.framer.com/docs/examples/#line-drawing

  • 코드

    const Svg = styled.svg`
      width: 300px;
      height: 300px;
      color: white;
      stroke: white;
      stroke-width:3;
    `
    const svg = {
      start: {
        fill: "rgba(255,255,255,0)",
        pathLength: 0
      },
      end: {
        fill: "rgba(255, 255, 255, 1)",
        pathLength: 1,
      }
    }
    
    return 
    	...
    			<Svg
            xmlns="<http://www.w3.org/2000/svg>"
            viewBox="0 0 488 512">
            <motion.path
              variants={svg}
              initial="start"
              animate="end"
              transition={{
                default: { duration: 3 },
                fill: { duration: 2, delay: 3 }
              }}
              d="M488 261.8C488 403.3 391.1 504 248 504 110.8 504 0 393.2 0 256S110.8 8 248 8c66.8 0 123 24.5 166.3 64.9l-67.5 64.9C258.5 52.6 94.3 116.6 94.3 256c0 86.5 69.1 156.6 153.7 156.6 98.2 0 135-70.4 140.8-106.9H248v-85.3h236.1c2.3 12.7 3.9 24.9 3.9 41.4z" />
          </Svg>

#7.11 AnimatePresence

조건부 showing

<AnimatePresence></AnimatePresence> 사이에 조건부 등장&삭제 기능이 있으면 animate 기능

initial=””, animate=””, exit=””

exit - 사라질때 발생할 애니메이션

  • 코드

    import { AnimatePresence } from "framer-motion";
    
    const boxxVariants = {
      start: {
        opacity: 0,
        scale: 0
      },
      end: {
        opacity: 1,
        scale: 1,
        rotateZ: 360
      },
      leaving: {
        opacity: 0,
        scale: 0,
        y: 50
      }
    }
    
    function ...
    	const [showing, setShowing] = useState(false);
      const toggleShowing = () => setShowing((prev) => !prev)
    
    return 
    		...
    		<button onClick={toggleShowing}>Click</button>
    		      <AnimatePresence >
    		        {showing ? <Box variants={boxxVariants} initial="start" animate="end" exit="leaving" /> : null}
    		      </AnimatePresence>

#7.12 ~ 13 Slider

next

prev

#7.13

custom

각 애니메이션 컴포넌트에 대해 동적 variants 를 다르게 적용할 때 사용하는 사용자 지정 데이터

  • 코드

    const Box = styled(motion.div)`
      width: 400px;
      height: 200px;
      display: flex;
      justify-content: center;
      align-items: center;
      background-color: rgba(255, 255, 255, 1);
      border-radius: 40px;
      font-size: 28px;
      box-shadow: 0 2px 3px rgba(0, 0, 0, 0.1), 0 10px 20px rgba(0, 0, 0, 0.06);
      position: absolute;
      top:100px;
    `
    const box = {
      start: (back: boolean) => ({
        x: back ? -500 : 500,
        opacity: 0,
        scale: 0,
        transition: { duration: 0.5 }
    }),
      end: {
        x: 0,
        opacity: 1,
        scale: 1,
        transition: {
          duration: 0.5,
        }
      },
      exit: (back: boolean) => ({
        x: back ? 500 : -500,
        opacity: 0,
        scale: 0,
        transition: { duration: 0.5 }
      }),
    }
    
    function ...
    const [visible, setVisible] = useState(1);
      const [back, setBack] = useState(false);
      const nextPlease = () => {
        setBack(false);
        setVisible((prev) => (prev === 10 ? 1 : prev + 1))
      }
      const prevPlease = () => {
        setBack(true);
        setVisible((prev) => (prev === 1 ? 10 : prev - 1))
      }
    
    return
    		... 
    			<AnimatePresence custom={back} mode="wait">
            <Box key={visible}  custom={back} variants={box} initial="start" animate="end" exit="exit">{visible}</Box>
          </AnimatePresence>
          <button onClick={prevPlease}>prev</button>
          <button onClick={nextPlease}>next</button>

#7.14

애니메이션을 적용하지 않아도 알아서 적용함

layout

변화 발생하면 자동 animation 적용

Animate between components

동일한 layoutId prop을 가진 모션 컴포넌트 간 애니메이션을 적용한다.

  • 코드

    const Circle = styled(motion.div)`
      background-color: #00a5ff;
      height: 100px;
      width: 100px;
      border-radius: 50px;
      box-shadow: 0 2px 3px rgba(0, 0, 0, 0.1), 0 10px 20px rgba(0, 0, 0, 0.06);
    `
    
    function ...
    	const [clicked, setClicked] = useState(false)
      const toggleClicked = () => setClicked((prev) => !prev)
    
    return ...
    		<Wrapper onClick={toggleClicked} style={{ background: gradient }}>
          <Box>
            {!clicked ? <Circle layoutId="circle" /> : null}
          </Box>
          <Box>
            {clicked ? <Circle layoutId="circle" /> : null}
          </Box>
        </Wrapper>

#7.15

#7.16

Motion

Last updated

Was this helpful?