[우아한테크코스 #2] Animation

NinjaJuunzzi·2022년 2월 19일
23

우아한테크코스

목록 보기
2/21
post-thumbnail
post-custom-banner

Animation 구현하기

애니메이션을 구현하는 방법에는 어떤 것들이 있을까요 ?!

  • css를 이용하여 구현한다.

  • requestAnimationFrame 전역 메소드를 활용하여 구현한다.

  • setTimeout, setInterval 메소드를 활용하여 구현한다.

우선 이번 어플리케이션은 프로그램 명세에 맞게 requestAnimationFrame 으로 애니메이션을 구현해보았습니다. 하지만 문득 이런 고민 들지않았나요?

다른 방식으로 짜면 구린건가..?

그래서 이번 절에선 세 개간 트레이드 오프를 간단하게나마 비교해보려고 합니다.

우선 이것을 알아두면 이해가 편할것 같아요

베이스 지식은 여기서!!

  • 브라우저의 렌더링 - layout(reflow) : 렌더 트리를 실제 뷰포트에 배치하는 과정

  • 브라우저의 렌더링 - paint(repaint) : 실제 브라우저 화면에 그리는 과정

  • 브라우저의 렌더링 - composite : 페인트 과정에서 분리하여 작업해놓았던 레이어들을 합성하는 과정

  • event loop가 관리하는 자료구조와 동작방식

1. CSS로 애니메이션 구현하기

CSS 기반 애니메이션과 기본 지원되는 웹 애니메이션은 일반적으로 컴포지터 스레드라고 불리는 스레드에서 처리됩니다. 이것은 스타일 지정, 레이아웃, 페인트 및 자바스크립트가 실행되는 브라우저의 메인 스레드와는 다릅니다.

메인스레드의 작업이 커진다면, JS Animation은 밀리게 되겠죠 ?! 하지만 CSS Animation 이라면 별개의 스레드에서 실행되므로 밀리지 않게 될것입니다.

애니메이션이 페인트 및/또는 레이아웃을 트리거하는 경우, 작업을 수행하기 위해 메인 스레드가 필요합니다. 이는 CSS 및 자바스크립트 기반 애니메이션에 모두 적용되며, 레이아웃 또는 페인트의 오버헤드는 CSS 또는 자바스크립트 실행과 연관된 모든 작업에 악영향을 미치고, 해결 불가능한 문제를 유발할 수 있습니다.

보통 많이 들었을테지만, reflowrepaint의 비용은 굉장히 크다고 소문이 나있죠. 이를 트리거 하는 애니메이션 속성들이 있을텐데 이를 피하는 것도 좋겠네요. 그게 뭔지 궁금하다면?

그래서 일단 CSS Animation의 장점은 제가 생각하기엔

  • 개발에 걸리는 시간과 노력이 비교적 덜 들어간다. (덜 복잡하다)

  • 관심사가 분리되어 유지보수에 편할것 같아요.

  • 메인스레드와 분리된 스레드에서 동작하기 때문에, 수행 시간을 보장받을 수 있을 것 같아요.

단점은 이럴거 같아요.

  • 애니메이션의 모든 단계에 대해 완벽한 제어가 힘들다.

2. JS로 애니메이션 구현하기

CSS Anmation과 비교하여 생각해본다면 다음과 같은 문제점이 있을 것 같아요

  • 관심사가 분리되지 않아 유지보수가 힘들다.

  • 메인스레드에서 동작하기 때문에 수행 시간을 보장받지 못할 수 있다.

그렇기 때문에 모든 애니메이션을 JS로 구현하면 좋지 않을 것 같아요.

하지만 애니메이션을 구현할 때, 애니메이션 도중에 세밀한 제어가 필요한 경우라면 이 메소드를 활용해볼 수 있을 것 같아요.

requestAnimationFrame vs setTimeout 으로 애니메이션 구현하기

결론부터 말씀드리자면, rAF로 애니메이션을 구현하는 경우 그 애니메이션은 부드럽습니다. 하지만 setTimeout으로 구현하는 경우 애니메이션은 부드럽지 않습니다. 왜 일까요?

박스가 돌아가는 애니메이션을 rAF를 함수로 구현해보겠습니다.

const box = document.querySelector(".box");

const rotateAnimation = (progress, start, node, during) => {
  if (progress >= during) {
    return;
  }

  node.style.transform = `rotate(${progress / 10}deg)`;

  requestAnimationFrame((timestamp) =>
    rotateAnimation(timestamp - start, start, node, during)
  );
};

requestAnimationFrame((timestamp) => rotateAnimation(0, timestamp, box, 5000));

함수가 어떤 명세를 따르는지 궁금하다면 ? 요기를 찾아보세요

박스가 돌아가는 애니메이션을 setTimeout으로 구현해보겠습니다. 재귀 방식을 사용하여 애니메이션을 구현해보았습니다.

const box = document.querySelector(".box");
function setTimer(timestamp, start) {
  const progress = timestamp - start;
  setTimeout(() => {
    box.style.transform = `rotate(${progress / 10}deg)`;
    setTimer(new Date().getTime(), start);
  }, 16);
}
setTimer(new Date().getTime(), 0);

구현은 위와 같이 할 수 있어요. 지금은 당연히 두 방식 다 부드럽게 애니메이션이 보일거에요. 그런데 왜 rAF Animation는 부드럽고, setTimeout Animation은 부드럽지 않다고 하는 걸까요?

task queue에 애니메이션 콜백만 있을까요?

1프레임 당 한번의 호출을 보장하는가

모니터 주사율이 60hz의 경우 화면 갱신 속도는 60fps이고, 이 때 1프레임은 16ms 정도 나와야한다.

rAF의 경우 1프레임당 호출이 보장됩니다. 이 때 렌더링 파이프라인에 진입했을 때 부터 다음 파이프라인에 진입하는 그 사이를 1프레임이라하구요.

rAF는 Animation frames라는 브라우저 렌더링과 관련된 task를 별도로 처리하는 queue를 통해 실행시점을 보증할 수 있습니다.

setTimeout의 경우 이벤트 루프가 관리하는 taskqueue 내부의 다른 task에 의해 지연될 수 있어 끊길 수 있을 것 같아요

setTimeout은 task queue에 올라가 동작하고, rAF는 렌더링 파이프라인과 붙어 동작하는 것을 확인할 수 있다. 이런 구조 상 rAF는 무조건 1프레임 당 1번의 호출이 보장되고 setTimeout은 지연되어 2프레임 당 1번, 또는 3프레임 당 1번 호출될 가능성도 있다.

느낀점

정리하자면, 단순한 애니메이션의 경우 (one-shot이자, 세부 제어가 필요없는 경우)라면 CSS Animation으로 작성하면 될 것 같아요. 그 외 복잡한 애니메이션이라면 JS Animation이 방안이 될 수 있을것이고, requestAnimationFrame 메소드를 통해 확실한 애니메이션을 표현해내면 되겠군요!

Ref

profile
Frontend Ninja
post-custom-banner

5개의 댓글

comment-user-thumbnail
2022년 2월 19일

정리 너무 깔끔하네요~ 많은 도움이 되었어요 :)

답글 달기
comment-user-thumbnail
2022년 2월 21일

최근에 requestAnimationFrame 쓸 일이 생겼는데 큰 도움이 되었습니다

답글 달기
comment-user-thumbnail
2022년 2월 21일

준찌 덕분에 rAF에 대해서 쉽게 이해할 수 있었어요.
저도 직접 코드에 적용할 수 있을 것 같은 자신감이 생기네요.
감사합니당 :)

답글 달기
comment-user-thumbnail
2022년 2월 25일

Good! Are you ready for this fresh version of HTML5? super smash flash 2 free

답글 달기
comment-user-thumbnail
2022년 5월 1일
답글 달기