브라우저가 변화된 화면을 그릴 준비가 됐을때, 최적화를 하여 애니메이션을 부드럽게 표현할 수 있는 기술
const rafCount = document.querySelector('.rafCount');
const rocket = document.querySelector('.rocket');
let rafValue;
const loop = () => {
rafValue = requestAnimationFrame(loop);
rafCount.innerHTML = `requestAnimationFrame return value is ${rafValue}`;
rocket.style.transform = `translateY(${-rafValue}px)`;
if (rafValue >= 550) cancelAnimationFrame(rafValue);
};
loop();
위의 코드는 아래에서 보여지는 동작에대한 코드이다.
기본 적으로 사용법은 어떻게 보면 재귀함수의 형태와 비슷하다.
requestAnimationFrame 의 return 값은 정수이고 짧은 시간에 수많은 값을 반환한다.
이는 초당 60프레임을 목표로한다. 하드웨어마다 성능이 다르므로, 60프레임을 목표로한다.
반환 되는 값이 정수이므로 조건을 통하여 함수의 종료도 가능하다.
함수를 종료시키고 싶으면, cancelAnimationFrame 을 사용하면된다.
위의 동작은 requestAnimationFrame 을 사용하지 않아도 충분히 구현할 수 있다.
그럼 어떤 상황에서 쓰이는지 알아보자.
노랑색은 requestAnimationFrame 을 적용하지 않은 것
초록색은 requestAnimationFrame 을 적용한 것
동작은 scroll event 에서 이루어지며, 키보드 방향키를 연타하여 이벤트를 발생시켰다.
초록색이 노란색보다 부드러운 것을 한눈에 알아볼 수 있다.
requestAnimationFrame 을 적용한 코드를 살펴보자.
해당 애니메이션은 속도를 감속시키는 계산식을 적용한 것이다.
(목표 지점 - 현재 지점) * 0.1 계산식을 설명해보자면, 목표 지점에서 현재 지점을 빼면 총 이동거리가 나오게되고 그 값에 10% 를 구한 것이다.
총 이동 거리는 계속 줄어들 것이고, 결국 0에 수렴할 것이다.
이러한 계산식으로 감속하는 애니메이션을 구현한다.
const box = document.querySelector('.box'); // orange
const box2 = document.querySelector('.box2'); // green
// requestAnimationFrame 을 줄여서 raf 라고 칭했다.
let acc = 0.1;
let delayedYOffset = 0;
let rafId;
let rafState;
window.addEventListener('scroll', () => {
box.style.width = `${window.pageYOffset}px`;
// cancelAnimationFrame 으로 함수를 취소하고나서, scroll event 가 발생할 때 다시 raf 를 실행시키는 로직
// rafState 가 false, 즉 raf 가 실행되고 있지 않다면 다시 loop 함수를 인자로 받은 raf 를 실행
if (!rafState) {
rafId = requestAnimationFrame(loop);
rafState = true;
}
});
function loop() {
delayedYOffset = delayedYOffset + (pageYOffset - delayedYOffset) * acc;
box2.style.width = `${delayedYOffset}px`;
rafId = requestAnimationFrame(loop);
// 현재위치 보다 - 되는 경우를 방지하기 위해 절대값 처리
// 목표 지점 - 현재 위치의 값이 1보다 작을경우 멈추게
if (Math.abs(pageYOffset - delayedYOffset) < 1) {
// raf 를 취소시킬 때, rafState 를 false 로 값을 할당.
cancelAnimationFrame(rafId);
rafState = false;
}
}
loop();
위와 같은 로직자체가 하나의 패턴이다. (부드러운 감속 애니메이션)
자주 사용될 수 있으니 알아두면 좋다.