불필요한 페인트 피하기 - 애니메이션 GIF 에디션

특히 모바일에서 부드럽고 원활한 프레임 속도를 달성하려면 페인트를 피하는 것이 중요합니다. 하지만 때로는 가장 예상치 못한 장소에 페인트가 나타나기도 합니다. 이 도움말에서는 애니메이션 GIF로 인해 불필요한 페인트가 발생하는 이유와 적용할 수 있는 매우 간단한 해결 방법을 살펴봅니다.

사랑스러운 레이어

아시다시피 최신 브라우저는 DOM 요소 그룹을 레이어라고 하는 별도의 '이미지'로 페인트할 수 있습니다. 페이지 전체에 하나의 레이어가 있는 경우도 있고, 수백 개, 드물게는 수천 개가 있는 경우도 있습니다.

DOM 요소가 레이어로 그룹화되어 있고 요소 중 하나가 시각적으로 변경되면 변경된 요소뿐만 아니라 변경된 요소와 겹치는 레이어의 다른 모든 요소도 페인트해야 합니다. 한 대상을 다른 대상 위에 페인팅하면 덮어쓰기된 픽셀이 영구적으로 '손실'됩니다. 원래 픽셀을 복구하려면 다시 페인트해야 합니다.

따라서 요소가 페인트될 때 변경되지 않은 다른 요소를 다시 페인트할 필요가 없도록 한 요소를 다른 요소와 격리해야 하는 경우가 있습니다. 예를 들어 고정된 페이지 헤더를 스크롤 가능한 콘텐츠와 결합하는 경우 콘텐츠가 스크롤될 때마다 헤더와 새로 표시되는 콘텐츠를 다시 그려야 합니다. 헤더를 별도의 레이어에 배치하면 브라우저에서 스크롤을 최적화할 수 있습니다. 스크롤하면 브라우저가 GPU의 도움을 받아 레이어를 이동하고 두 레이어를 모두 다시 칠하지 않을 수 있습니다.

레이어를 추가할 때마다 메모리 사용량이 증가하고 성능 오버헤드가 추가되므로, 좋은 성능을 유지하면서 페이지를 최대한 적은 수의 레이어로 그룹화하는 것이 목표입니다.

애니메이션 GIF와 어떤 관련이 있나요?

이 사진을 한 번 살펴보겠습니다.

4개의 레이어로 분류된 웹 앱
그림 1: 4개의 레이어로 분류된 웹 앱

다음은 간단한 앱의 잠재적 레이어 설정입니다. 여기에는 4개의 레이어가 있습니다. 그중 3개 (레이어 2~4)는 인터페이스 요소이고 뒷 레이어는 애니메이션 GIF인 로더입니다. 일반적인 흐름에서는 앱이 로드되는 동안 로더 (레이어 1)를 표시한 다음 모든 작업이 완료되면 다른 레이어를 표시합니다. 하지만 중요한 점은 애니메이션 GIF를 숨겨야 한다는 것입니다.

하지만 왜 숨겨야 하나요?

좋은 질문입니다. 이상적인 상황에서는 브라우저가 GIF의 가시성을 확인하고 자동으로 페인팅을 방지합니다. 안타깝게도 애니메이션 GIF가 화면에 가려져 있는지 또는 표시되는지 확인하는 작업은 일반적으로 단순히 그리기보다 더 비싸기 때문에 그려집니다.

가장 좋은 경우 GIF가 자체 레이어에 있고 브라우저는 GIF를 페인트하고 GPU에 업로드하기만 하면 됩니다. 하지만 최악의 경우 모든 요소가 단일 레이어로 그룹화되어 브라우저가 모든 요소를 다시 칠해야 할 수 있습니다. 완료 후에도 모든 항목을 GPU에 업로드해야 합니다. 사용자가 GIF를 볼 수 없는데도 모든 GIF 프레임에 대해 이러한 작업이 실행됩니다.

데스크톱에서는 CPU와 GPU가 더 강력하고 두 기기 간에 데이터를 전송할 수 있는 충분한 대역폭이 있으므로 이러한 종류의 페인팅 동작을 사용할 수 있습니다. 하지만 모바일에서는 페인팅이 매우 비싸므로 주의해야 합니다.

어떤 브라우저가 영향을 받나요?

일반적으로 브라우저마다 동작이 다릅니다. 현재 Chrome, Safari, Opera는 GIF가 가려져 있더라도 모두 다시 렌더링합니다. 반면 Firefox는 GIF가 가려져 있고 다시 칠할 필요가 없다고 판단합니다. Internet Explorer는 여전히 블랙박스 상태이며, F12 도구가 아직 개발 중이므로 IE11에서도 다시 칠하는지 여부를 알 수 없습니다.

이 문제가 있는지 어떻게 알 수 있나요?

가장 쉬운 방법은 Chrome DevTools에서 '페인트 직사각형 표시'를 사용하는 것입니다. DevTools를 로드하고 오른쪽 하단의 톱니바퀴 (톱니바퀴 아이콘)를 누른 다음 렌더링 섹션에서 페인트 직사각형 표시를 선택합니다.

Chrome DevTools 내에서 페인트 직사각형 표시 사용 설정
그림 2: Chrome DevTools 내에서 'Show paint rectangles'(페인트 직사각형 표시)를 사용 설정합니다.

이제 다음과 같은 빨간색 직사각형을 찾기만 하면 됩니다.

DevTools의 '페인트 직사각형 표시'는 빨간색 직사각형으로 애니메이션 GIF 문제를 나타냅니다.
그림 3: DevTools의 'Show Paint Rectangles'(페인트 직사각형 표시)에 빨간색 직사각형으로 애니메이션 GIF 문제가 표시됩니다.

화면에 있는 작은 빨간색 상자는 Chrome에서 무언가를 다시 칠하고 있음을 나타냅니다. 다른 요소 뒤에 로더 GIF가 숨겨져 있으므로 이와 같은 빨간색 상자가 표시되면 표시된 요소를 숨기고 애니메이션 GIF가 계속 회전하고 있는지 확인해야 합니다. 있다면 CSS 또는 JavaScript를 팝하여 요소 또는 상위 요소에 display: none 또는 visibility: hidden를 적용해야 합니다. 물론 배경 이미지인 경우에는 삭제해야 합니다.

실시간 사이트에서 이 동작의 예를 보려면 Allegro를 확인하세요. 각 제품 이미지에 명시적으로 숨겨지는 대신 가려지는 로더 GIF가 있습니다.

결론

60fps를 달성한다는 것은 페이지를 렌더링하는 데 필요한 작업만 실행한다는 의미입니다. 이 목표를 달성하려면 과도한 페인트를 제거하는 것이 중요합니다. 실행 상태로 두면 애니메이션 GIF가 불필요한 페인트를 트리거할 수 있습니다. DevTools의 페인트 직사각형 표시 도구를 사용하면 이러한 페인트를 쉽게 찾고 디버그할 수 있습니다.

애니메이션 고양이 로더 GIF를 계속 실행하지는 않으셨겠죠?