Technote

성능 최적화 실무

움직여도 되는 속성과 프레임을 갉아먹는 속성

한 프레임에 허락된 시간은 아주 짧습니다. transform 과 opacity 만이 레이아웃 계산 없이 움직이고, 나머지는 매 프레임 값을 치릅니다.

애니메이션이 끊겨 보이는 화면은 대개 애니메이션이 많아서가 아니라 잘못된 속성을 움직여서 생깁니다. 같은 움직임이라도 어떤 속성으로 구현했느냐에 따라 브라우저가 하는 일의 양이 크게 다릅니다.

한 프레임 안에서 브라우저가 하는 일

부드러운 움직임은 초당 60프레임 근처에서 만들어집니다. 즉 한 프레임에 허락된 시간이 16밀리초 남짓이고, 그 안에 브라우저는 다음 순서를 밟아야 합니다.

렌더링 파이프라인 — 뒤쪽에서만 일하는 애니메이션이 싸다

핵심은 어느 단계부터 다시 하느냐입니다. 요소의 크기나 위치를 바꾸는 속성은 레이아웃부터 다시 계산합니다. 이 요소만이 아니라 형제와 부모의 배치까지 영향을 받으므로 비용이 가장 큽니다. 색이나 그림자를 바꾸면 레이아웃은 건너뛰지만 페인트를 다시 합니다. 그리고 transformopacity 만은 합성 단계에서 처리되어, 앞의 두 단계를 건드리지 않습니다.

같은 움직임을 싸게 만드는 치환

대부분의 UI 애니메이션은 싼 속성으로 바꿔 쓸 수 있습니다. 결과가 눈에 거의 같으면서 브라우저가 하는 일만 줄어듭니다.

왼쪽을 오른쪽으로 옮기는 것이 성능 작업의 대부분이다

구체적으로는 이렇습니다. 요소를 옆으로 미는 애니메이션은 left 가 아니라 translateX 로, 커지는 효과는 width 가 아니라 scale 로 만듭니다. 사라지는 효과는 displayheight 를 건드리지 말고 opacity 로 처리합니다. 그림자가 짙어지는 효과가 필요하면, 그림자 값을 애니메이션하는 대신 짙은 그림자를 가진 겹을 하나 더 두고 그 겹의 투명도만 움직입니다.

will-change 는 도움이 되지만 남용하면 역효과입니다. 이 속성은 브라우저에게 별도 레이어를 미리 준비하라고 알리는 것이고, 레이어마다 메모리를 씁니다. 실제로 곧 움직일 요소에만, 움직임이 끝나면 해제하는 것이 원칙입니다.

예산을 세웁니다 — 개수 · 길이 · 동시성

속성을 잘 골라도 한꺼번에 수십 개를 움직이면 여전히 느립니다. 디자인 단계에서 세 가지를 정해 두면 구현이 편해집니다.

애니메이션 예산 — 아래 두 줄이 프레임을 가장 많이 갉아먹는다

아래에서 두 번째 줄을 설명해 두겠습니다. 스크롤할 때마다 자바스크립트로 요소의 위치를 읽고 스타일을 바꾸면, 브라우저는 읽기 요청 때문에 진행 중이던 계산을 강제로 끝내야 합니다. 프레임마다 이것이 반복되면 스크롤이 눈에 띄게 무거워집니다. 요즘은 CSS 만으로 스크롤에 연동된 효과를 만들 수 있으므로, 이 계열의 효과는 스타일시트 쪽으로 옮기는 편이 안전합니다.

모션을 줄여 달라는 요청은 실제 요청입니다

운영체제에는 움직임을 줄여 달라는 설정이 있고, 브라우저는 그 값을 prefers-reduced-motion 으로 전달합니다. 어지럼증이나 전정기관 문제로 애니메이션이 불편한 사용자에게 이것은 취향이 아니라 필요입니다.

대응에서 중요한 것은 기본값이 완성된 상태여야 한다는 점입니다. 애니메이션 선언 안에서만 요소를 보이게 만들면, 모션을 끈 사용자에게는 콘텐츠가 아예 나타나지 않습니다. 정적 상태를 먼저 완성해 두고 움직임을 그 위에 얹으면, 모션을 꺼도 지원하지 않는 브라우저에서도 화면은 온전합니다.

프레임 예산과 함께 봐야 할 첫 화면 성능 주제는 성능 최적화 아카이브에 모여 있고, 화면 폭에 따라 움직임을 조절하는 방법은 반응형 연재에서 다룹니다. 실제 사이트의 렌더링 병목을 찾아 고치는 작업은 최적화 지원 사업에 포함됩니다.

이 주제의 다른 글

노하우 목록으로

성능 최적화 실무

태그 하나가 더하는 밀리초는 누가 냅니까

추적 스크립트는 내려받고 끝나지 않습니다. 파싱과 실행이 메인 스레드를 점유하는 동안 페이지는 손가락에 반응하지 않습니다. 그 비용은 직접 잴 수 있습니다.

마케터 3분 읽기

₩270,000 · 신청하기