자바스크립트로 스타일을 변경한다면 rAF(requestAnimationFrame)를 사용해보세요!
글을 시작하며 보통 웹 페이지의 애니메이션을 구현할 때, 리페인트를 방지하고자 CSS의 animation, transition, transform 속성을 통해 구현을 할 수 있지만 보다 사용자와의 복잡한 상호작용을 구현하게 하기 위해서 자바스크립트를 활용해 스타일을 변화시켜야하는 경우도 있어요. 특정 영역을 클릭하거나, 웹 페이지를 스크롤 할 때 변화무쌍한 애니메이션 작업들이 그러해요. 간단하고 규칙적인 애니메이션은 CSS로만 요소의 좌표값이나, 스타일 크기를 변화시키고 세밀하고 디테일한 변화를 필요로하는 애니메이션의 경우에는 자바스크립트로 스타일 속성을 변경시키는 편인데요, 하지만 자바스크립트로 스타일을 변경시키게 되면 대개 너비 또는 위치 값을 변경시키는 요소들이기에 일반적인 CSS보다 성능이 좋지 못해요. 따라서 어쩔 수 없이 자바스크립트와의 상호 협력이 필요한 경우에는 이를 위한 최적화 기법이 필요해요. 브라우저 렌더링 단계 위에서 언급했듯 리페인트가 무엇인지, 리플로우가 무엇인지 한번 확인을 해볼게요. 브라우저는 위와 같은 과정들을 통해 브라우저 파이프라인을 그려요. JavaScript : 애니메이션 및 기타 작업 스크립트를 수행 (DOM 생성) Style : CSS 규칙을 어떤 요소에 적용할지 계산하는 과정 수행 (CSSOM 생성) Layout (Reflow) : 브라우저는 DOM과 CSSOM을 결합해 객체들의 위치와 크기 등을 계산하는 렌더 트리를 생성 Paint (Repaint) : 브라우저는 렌더 트리를 사용해 실제로 화면에 픽셀을 출력 (객체가 실제 화면에 그려지는 것을 의미) Composite : 브라우저는 화면에 출력되는 객체들을 합성해 최종 화면을 생성 (최적화 과정) 브라우저 프레임 60hz, 120hz과 같은 모니터 주사율이 있다고 했을 때, 이는 1초 동안 모니터 화면의 출력 빈도를 의미해요. 영화 또는 애니메이션을 보는 과정은 사실 짧은 간격으로 이루어진 사진을 이어보는 과정이에요. 이 각각의 장면을 frame이라고 칭하는데, 특정 시간 내에 보여지는 frame 갯수를 frame rate 혹은 frame per second (fps)라고 해요. 보통 사람의 눈은 1초에 60번 장면이 넘어가야 부드럽게 느낀다고 하며, 그래서 현재 기기들은 시각적인 효과를 위해 초당 60번 화면을 다시 그리도록 기본적으로 설계되어있어요. 이를 60fps 혹은 60hz라고 불리우는 이유예요. 웹 화면에서 부드러운 효과를 제공하기 위해서는 이 프레임 단위에 맞게 설계해야하기 때문에, 초당 60개의 프레임을 렌더링 한다는 말은 16.666ms(1000ms / 60fps) 간격으로 프레임 생성이 필요한 셈이 돼요. 따라서 자바스크립트로 사용자에게 부드러운 애니메이션을 구현하려면 16.6ms 마다 코드를 호출하는 식으로 구현해야해요. 타이머 함수로 60fps 제공하기 아래와 같이 setInterval과 setTimeout을 통해 60fps를 제공하는 코드를 작성해보았어요. 위와 같이 타이머 함수를 작성하게 되면 주어진 시간 내에 동작은 하겠지만, 프레임을 신경쓰지 않고 동작하는 문제점이 발생한다. 타이머 함수는 프레임 단위로 프레임 시작 시간에 맞춰 실행됨을 보장하기 못하기 때문이에요. 약 16ms 간격으로 프레임 단위가 진행되어야하는데, 만약 브라우저가 다른 작업 수행으로 인해 지연되어 자바스크립트의 콜백 코드가 프레임 단위 중간에서 호출되면 자바스크립트 실행에 의해 리플로우가 발생하면서 브라우저 렌더링 단계인 레이아웃 - 페인트 - 합성 과정이 다시 일어나는데, 이때 프레임이 생성되지 못하고 누락되어 프레임이 깎이는 현상이 발생할 수 있기 때문이에요. 위와 같은 이유 때문에 프레임 드랍이 일어나 지연 현상이 발생하고, 화면이 버벅이는 현상이 발생한다. 이를 해결하기 위해 대안으로 나온 것이 rAF (requestAnimationFrame)이에요. requestAnimationFrame rAF(requestAnimationFrame) 함수는 시스템이 프레임을 그릴 준비가 되면 애니메이션 프레임을 호출하여 애니메이션 웹 페이지를 보다 원활하고 효율적으로 생성할 수 있도록 해줘요. 실제 화면이 갱신되어 표시되는 주기에 따라 함수를 호출해주기 때문에 프레임 시작 시 콜백이 실행되도록 보장해주어 프레임 드랍과 같은 밀림 현상을 방지해줘요. rAF(requestAnimationFrame) 함수가 실행되면 브라우저는 다음 프레임이 그려지기 전에 함수를 실행하도록 예약하기 때문에 각 프레임이 정확히 16.6ms 간격으로 렌더링되게 돼요.
- 프론트엔드
- 김현우김