jQuery 없이 애니메이션 사용하기

개발

jQuery 없이 애니메이션 사용하기
최종 수정일:

애니메이션 대부분은 JS에선 엘리먼트의 class 정도만 변경해주고 CSS에서 애니메이션을 추가하는 방식으로 사용하실 수 있습니다.
하지만, 엘리먼트의 width나 height을 변경하거나, 특정 엘리먼트까지 부드럽게 스크롤 하는 덴 위 방식으로 한계가 있습니다.
엘리먼트의 width나 height을 css의 transition으로 변경하면 60FPS 보장이 굉장히 힘들어지고, scroll-behavior은 사파리에서 지원하지 않기 때문입니다.

jQuery에선 .animate(), .slideToggle() 등으로 간단히 작업할 수 있는데, 이를 바닐라로 비슷하게 구현해봤습니다.

function animateScroll(to) {
    function animation() {
        const now = (performance.now() - startTime) / time,
            progress = transition(now);
 
        1 > now
        ? (
            window.requestAnimationFrame(animation),
            window.scrollTo(0, from + (to - from) * progress)
        )
        : (
            window.scrollTo(0, to)
        )
    }
 
    const from = window.scrollY;
    const time = 500,
        transition = number => {
            return -.5 * (Math.cos(Math.PI * number) - 1)
        },
        startTime = performance.now();
    animation()
}

특정 위치까지 부드럽게 스크롤 해주는 스크립트입니다.
animateScroll(숫자), animateScroll(엘리먼트.offsetTop)
같은 방식으로 사용하시면 됩니다.

time은 애니메이션이 진행될 시간(ms)입니다.

transition 함수는 css의 transition에 넣는 ease-in-out 같은 역할을 해주는 함수입니다. (easing function이라 부릅니다.)
정의역은 0 ~ 1까지 실수입니다. 특별한 애니메이션을 만들 게 아니라면 (0,0)에서 (1,1)까지 가도록 하시는 게 좋습니다.

f(x)=-0.5(cos(pi*x)-1)

f(x) = -0.5(cos(pi*x)-1)

위 함수에서 animation() 함수에 들어있는 window.scrollTo와 from, to를 수정하시면 원하는 애니메이션을 제작하실 수 있습니다.

function slideToggle(element) {
    function animation() {
        const now = (performance.now() - startTime) / time,
            progress = transition(now);
 
        1 > now
        ? (
            window.requestAnimationFrame(animation),
            element.style.height = `${from + (to - from) * progress}px`
        )
        : (
            element.style.height = `${to}px`
        )
    }
    const status = element.dataset.expand ? element.dataset.expand === "1" : element.offsetHeight;
    const from = element.offsetHeight;
    let to = 0;
 
    status
    ? (
        element.dataset.expand = 0
    )
    : (
        element.dataset.expand = 1,
        element.style.height = "auto",
        to = element.offsetHeight,
        element.style.height = 0,
        void element.offsetHeight
    );
 
    const time = 300,
        transition = number => {
            return -.5 * (Math.cos(Math.PI * number) - 1)
        },
        startTime = performance.now();
    animation()
}

다른 예시로 jQuery의 slideToggle()을 구현해봤습니다.
data-expand 란 attribute을 생성해 엘리먼트의 상태를 확인하고, 펼쳐진 상태면 to를 0으로, 그렇지 않으면 offsetHeight을 측정해 그 값으로 설정합니다.

외에도 전 홈 화면 슬라이더를 움직이는 애니메이션도 위 스크립트를 활용해 제작해뒀습니다.
animateScroll()만 제대로 보셔도 애니메이션 대부분에 활용하실 수 있습니다.

Report an issue