본문 바로가기
Frontend/- Framer motion

Framer motion : scroll Animation에 대하여

by 코딩쥐 2024. 9. 28.

Framer motion에서 scroll animation 기능은 스크롤과 연동된 애니메이션을 구현할 수 있도록 도와준다. 크게는 (1) scroll-linked animation (스크롤 진행에 따라 애니메이션이 직접적으로 연동되는 방식)과 (2) scroll-triggered animation (요소가 뷰포트에 들어오간 나갈 때 애니메이션이 트리거 되는 방식)으로 나눈다. 

 

Scroll-linked animation

scroll-linked animation 은 useScroll 훅을 통해서 스크롤과 연동된 애니메이션을 구현한다. 

  • scrollX / scrollY : 페이지의 수평 및 수직 스크롤 위치를 픽셀 단위로 반환한다.
  • scrollXProgress / scrollYProgress : 페이지의 수평 및 수직 위치를 0과 1 사이의 값으로 반환한다.

 

1. useScroll에서 기능을 가져온다. 

아래 예제에서는 scrollYProgress (수직 위치를 0과 1 사이의 값으로 반환) 을 가져왔다. 0은 페이지의 최상단, 1은 페이지의 최하단을 의미한다.

import { useScroll } from "framer-motion";

const Scrollexample = () => {
    const {scrollYProgress} = useScroll();
}

export default Scrollexample;


2. scrollYProgress로 애니메이션을 적용한다.

scrollYProgress를 사용하여 motion.div의 scaleX 프로퍼티를 조정하면, 페이지 스크롤에 따라 프로그레스 바의 길이가 변하도록 설정할 수 있다.

import { useScroll, motion } from "framer-motion";
import styles from "./css/Scrollexample.module.css"

const Scrollexample = () => {
    const { scrollYProgress } = useScroll();

    return (
        <div className={styles.container}>
            <motion.div style={{ scaleX: scrollYProgress }} className={styles.bar} />
        </div>
    )
}

export default Scrollexample;

 

 

만약 전체적인 스크롤이 아니라, 특정 요소의 스크롤 위치를 추적해서 해당하는 애니메이션을 적용하고 싶으면 ref와 함께 사용하면 된다. useRef를 정의하고, useScroll을 useRef를 사용하여 정의한다. 

import { useScroll, motion } from "framer-motion";
import { useRef } from "react";

export default function Comp01() {
    const scrollRef = useRef(null);
    const { scrollXProgress } = useScroll({ container: scrollRef });
    return (
        <div>
            <motion.div style={{ scaleX: scrollXProgress, height: "300px", backgroundColor: "lightgray" }} />
            <div ref={scrollRef} style={{ width: "800px", overflowX: "scroll" }}>
                <div style={{ width: "200vw", height: "300px", background: "lightblue" }}/>
            </div>
        </div>
    )
}


scroll-triggered animation

요소가 뷰포트에 들어오간 나갈 때 애니메이션이 트리거 되는 방식으로 whileInView를 통해 이러한 애니메이션을 만들 수 있다. 

속성 설명
whileInView 요소가 뷰포트에 있을 때 애니메이션 정의
viewport 뷰포트를 정의하는 옵션  (뷰포트의 크기나 위치를 조정)
onViewportEnter(entry) 요소가 뷰포트에 들어올 때 호출되는 함수
onViewportLeave(entry) 요소가 뷰포트를 벗어날 때 호출되는 함수

 

viewport 속성에 사용되는 옵션

옵션 설명
once 요소가 뷰포트에 들어올 때 애니메이션을 한 번만 실행할지를 결정
root 뷰포트를 기준으로 할 요소를 지정
margin 뷰포트와 요소 간의 간격을 설정 (기본값 : "0px")
amount 요소가 뷰포트에 얼마나 들어와야 애니메이션을 트리거할지를 정의 (기본값: "some")
amount의 경우에는 데스크탑 기준이기때문에 반응형 웹에서는 사용이 제대로 안된다.
import { motion } from "framer-motion";
import './css/Comp01.css';

export default function Comp01() {
    return (
        <div className="container">
            {/* 첫 번째 요소 */}
            <motion.div
                className="box"
                initial={{ opacity: 0, scale: 0.5 }}
                whileInView={{ opacity: 1, scale: 1 }}
                viewport={{ once: true }} // 애니메이션을 한 번만 실행
                transition={{ duration: 0.5 }}
            >
                <h2>첫 번째 요소</h2>
            </motion.div>

            {/* 두 번째 요소 */}
            <motion.div
                className="box"
                initial={{ opacity: 0, x: -100 }}
                whileInView={{ opacity: 1, x: 0 }}
                viewport={{ margin: "0px 0px -50% 0px" }} // 하단에서 -50% 지점에서 애니메이션 시작
                transition={{ duration: 0.5 }}
            >
                <h2>두 번째 요소</h2>
            </motion.div>

            {/* 세 번째 요소 */}
            <motion.div
                className="box"
                initial={{ opacity: 0, y: 100 }}
                whileInView={{ opacity: 1, y: 0 }}
                viewport={{ amount: 0.5 }} // 요소의 50%가 보일 때 애니메이션 시작
                transition={{ duration: 0.5 }}
            >
                <h2>세 번째 요소</h2>
            </motion.div>
        </div>
    );
}

 

만약 전체적인 스크롤이 아니라, 특정 요소의 스크롤 위치를 추적해서 해당하는 애니메이션을 적용하고 싶으면 ref와 함께 사용하면 된다. useRef를 정의하고, viewport={{root : ref변수명}} 으로 속성을 정의하면 된다.