[CSS] requestAnimationFrame

Eden·2023년 1월 16일
1

HTML & CSS

목록 보기
6/7
post-thumbnail
post-custom-banner

requestAnimationFrame()(이하 raf)은 브라우저에게 수행하기를 원하는 애니메이션을 알리고 다음 repaint가 진행되기 전에 해당 애니메이션을 업데이트하는 함수를 호출하게 한다.

쉽게 말해서 브라우저가 이제 매번 계속 화면을 그리는데, 변화된 화면을 그릴 준비가 완료 되었을 때 딱 그려준다고 볼 수 있다. 무언가를 최적화를 해서 애니메이션을 부드럽게 처리하는 기술이라고 생각하면 될 것 같다.

이전에는 setInterval()을 사용했지만, setInterval()은 프레임 유실이나 모바일 기기에서 배터리 사용량이 많아져 raf가 등장한 이후에는 주로 raf를 사용하고 있다.

requestAnimationFrame() 사용법

window.requestAnimationFrame(callback);

callback : 다음 repaint를 위한 애니메이션을 업데이트할 때 호출할 함수.

예시를 들어 사용해보자.

기본 사용법

  <body>
    <img class="image" src="/이미지경로" />
    <div class="value">requestAnimationFrame</div>

    <script>
      const image = document.querySelector(".image");
      const value = document.querySelector(".value");

      requestAnimationFrame(() => {
        console.log(0);
      });

      console.log(1);
    </script>
  </body>

보기에서 console의 순서가 어떻게 될까요?

//console창
1
0

아래에 있는 console이 먼저 실행되고, raf안에 있는 console이 나중에 실행되는 걸 알 수 있고, 그리고 한 번씩만 실행이 된다.
여기서 알 수 있는 사실은 raf에는 지연효과가 있다는 사실을 기억해야한다! 기본적인 동작은 이렇게 되고, 함수에서 사용해보자!

함수 안에서 사용해보기

<body>
	<div class="container">
      <img class="image" src="/이미지경로" />
      <div class="value">requestAnimationFrame</div>
    </div>
	<script>
		const image = document.querySelector(".image");
		const value = document.querySelector(".value");
		//2 yPos라는 변수를 하나 만들고 값을 0으로 줍니다.
		let yPos = 0;


        //1 render라는 함수 생성
        const render = () => {
            //3 innerHTML로 yPos를 출력
            value.innerHTML = yPos;
            //4 yPos 증가
            yPos++
            //6 애니메이션
            requestAnimationFrame(render);
        }
        //5 render 함수 실행
        render();
   </script>
</body>
  1. render라는 함수를 만들고
  2. yPos라는 변수를 하나 만들고 값을 0으로 준다.
  3. 그 다음에 valueinnerHTMLyPos를 출력을 하고,
  4. yPos를 1씩 올려보고,
  5. 이 상태에서 render()를 호출하면 0이 찍힌다.

*여기서 innerHTML로 출력을 한다음에 1을 더했으니까 아직은 1을 더한게 의미가 없다.

  1. 그런데 우리가 애니메이션을 주기위해선 render함수를 아주 빠른 속도로 반복을 시키려고 한다. 그 때 우리가 여기다가 requestAnimationFrame를 써주고 콜백함수 자리에 render함수를 넣어주고 (5)의 render()를 실행하면 이렇게 아주 빠른속도로 1씩 증가하게 된다.

이 속도는 초당 60번을 목표로 하지만, 현재 컴퓨터의 상황이나 성능, 기타 등등 요소에 따라서 속도는 더 느려질 수 있다.. 어쨌든 초당 60회 가까이 반복을 하려고 노력을 하는 중이라는거..? 애니메이션으로 치면 60프레임을 목표로 빠르게 돌아간다.






그럼 이제 이미지를 가지고 raf를 이용해서 애니메이션을 구현해보자.

예제

<body>
	<div class="container">
      <img class="image" src="/이미지경로" />
      <div class="value">requestAnimationFrame</div>
    </div>
	<script>
		const image = document.querySelector(".image");
		const value = document.querySelector(".value");		
		let yPos = 0;

        const render = () => {
	  		value.innerHTML = yPos;
            //2 이미지의 스타일의 transform을 translateY로 이동시키게 하기
          	image.style.transform = `translateY(${-yPos}px)`;
          //1 변화하는 변수 값
            yPos++;

          	requestAnimationFrame(render);
    	};

		render();
   </script>
</body>

위에서 사용한 예시에 이미지 경로에 지정한 이미지를 가지고 raf를 이용해서 애니메이션을 만들려면
1. 변화하는 변수 값을 이미지의 y position 값으로 쓰고
2. 이미지 스타일의 transform을 translateY로 이동을 시켜볼게여 translateY안에 yPos값 px만큼 움직일 수 있게 지정해준다.

이제 이렇게 되면 애니메이션이 아주 잘 작동을 하게 된다.

그치만 아직까진 can't stop ...

🔻멈추는 방법에 대해서 알아보자🔻

cancelAnimationFrame() 사용법

cancelAnimationFrame(requestAnimationFrame(callback));

예제

//클릭하면 애니메이션 멈추게
<body>
	<div class="container">
      <img class="image" src="/이미지경로" />
      <div class="value">requestAnimationFrame</div>
    </div>
	<script>
		const image = document.querySelector(".image");
		const value = document.querySelector(".value");		
		let yPos = 0;
		//1
		let rafId;

        const render = () => {
	  		value.innerHTML = yPos;
          	image.style.transform = `translateY(${-yPos}px)`;
          	yPos++;
			//2
          	rafId = requestAnimationFrame(render);
    	};

		render();

		window.addEventListener("click", () => {
        cancelAnimationFrame(rafId);
      });
   </script>
</body>
  1. rafId라는 변수를 일단 만들고,
  2. rafId에 raf를 담아봤습니다.

만약 여기서 rafId를 console에 찍으면 뭐가 나올까여
console.log(rafId);

//console창
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
.
.
.
100
.
.
.
♾️

그냥 1씩 늘어나면서 숫자가 찍힌다.

그래서 우리는 rafId가 숫자로 리턴이 된다는 걸 알 수가 있고 2번의 rafId 값을 이용해서 멈출 수가 있다.

어떻게 하냐하면 바로,

cancelAnimationFrame()을 해주고 매개변수 자리에 인자로 rafId를 넣어주면 된다.
그리고 클릭하면 애니메이션이 멈춘다..!

그럼 이제 나는 raf를 사용해봤다고 할 수 있겠다.

profile
Just living the daydream, one moment at a time.
post-custom-banner

0개의 댓글