CSS 애니메이션 & 성능 문제

Category
OpenSource
Status
Published
Tags
OpenSource
CSS
Description
Published
Slug

1. 애니메이션은 어떻게 만들어질까?

컴퓨터 화면 = 연속된 사진들

영화 = 초당 24장의 사진을 빠르게 보여줌 웹 애니메이션 = 초당 60장의 화면을 빠르게 보여줌 (60 FPS)
 

웹 애니메이션 방식 2가지

CPU 방식 (Main Thread) - 느림

브라우저: "높이를 100px에서 200px로 바꿔라" 1. HTML 다시 계산 (Reflow) 2. CSS 스타일 다시 계산 (Recalculate) 3. 화면 다시 그리기 (Repaint) 4. 다른 요소들도 영향받아서 다시 배치 → 60번/초 하면 버벅거림

GPU 방식 (Compositor) - 빠름

그래픽카드: "이미 그려진 이미지를 움직이기만 하면 됨" 1. 이미 완성된 이미지를 3D 공간에서 이동 2. 다른 요소들 건드리지 않음 → 60번/초도 부드럽게

 

2. CSS 속성이 문제되는 부분

CPU에서만 처리되는 속성들 (느림)

/* 레이아웃을 변경하는 속성들 */ height: 100px → 200px; /* 높이 변경 = 전체 레이아웃 재계산 */ width: 100px → 200px; /* 너비 변경 = 전체 레이아웃 재계산 */ margin: 10px → 20px; /* 여백 변경 = 주변 요소들 위치 변경 */ padding: 5px → 10px; /* 내부 여백 = 내용물 위치 변경 */ top: 0px → 100px; /* 위치 변경 = 레이아웃 재계산 */ left: 0px → 100px; /* 위치 변경 = 레이아웃 재계산 */ /* 그리기를 다시 해야 하는 속성들 */ background-color: red → blue; /* 배경색 = 다시 칠하기 */ color: black → white; /* 글자색 = 다시 칠하기 */ border: 1px → 5px; /* 테두리 = 다시 그리기 */

GPU에서 처리되는 속성들 (빠름)

/* 이미 그려진 것을 3D 공간에서 조작 */ transform: translateX(100px); /* 이동만 함 */ transform: scale(1.2); /* 크기만 변경 */ transform: rotate(45deg); /* 회전만 함 */ opacity: 0.5; /* 투명도만 변경 */

3. 실제 예시

나쁜 예시 (버벅거림)

.box { transition: height 0.3s ease; } .box:hover { height: 200px; /* CPU가 60번/초 레이아웃 재계산 = 버벅 */ }
브라우저 내부 상황
0.000초: height: 100px → 레이아웃 계산 → 화면 그리기 0.016초: height: 103px → 레이아웃 계산 → 화면 그리기 0.032초: height: 106px → 레이아웃 계산 → 화면 그리기 ... (매번 전체 페이지 재계산)
 

좋은 예시 (부드러움)

.box { transition: transform 0.3s ease; } .box:hover { transform: scaleY(2); /* GPU가 이미 그려진 것만 늘림 = 부드러움 */ }
브라우저 내부 상황
0.000초: transform: scaleY(1.0) → GPU에서 즉시 처리 0.016초: transform: scaleY(1.1) → GPU에서 즉시 처리 0.032초: transform: scaleY(1.2) → GPU에서 즉시 처리 ... (다른 요소들 건드리지 않음)

 

4. 커스텀 CSS 변수란?

일반적인 CSS

.button1 { background-color: #3498db; } .button2 { background-color: #3498db; } .button3 { background-color: #3498db; } /* 같은 색을 계속 반복 */

커스텀 CSS 변수 (CSS Custom Properties)

:root { --main-color: #3498db; /* 변수 정의 */ --spacing: 20px; --animation-duration: 0.3s; } .button1 { background-color: var(--main-color); } .button2 { background-color: var(--main-color); } .button3 { background-color: var(--main-color); } /* 한 곳만 바꾸면 모든 곳이 바뀜 */

JavaScript로 동적 변경

// 테마 색상을 즉시 변경 document.documentElement.style.setProperty('--main-color', '#e74c3c'); // → 모든 --main-color 사용하는 곳이 빨간색으로 변경!

 

5. 커스텀 변수 애니메이션의 문제

문제가 되는 코드

:root { --box-height: 100px; } .box { height: var(--box-height); transition: height 0.3s ease; } .box:hover { --box-height: 200px; /* 커스텀 변수 값 변*/ }
 
겉보기에는 문제가 없어 보이지만, 브라우저 내부에서는 비효율적인 과정이 발생
이는 height 속성 자체가 가진 특징 때문
 

브라우저의 렌더링 과정과 문제점

브라우저는 웹페이지를 화면에 그리기 위해 다음과 같은 과정을 거침
  1. Layout (Reflow): 각 요소의 크기와 위치를 계산. "이 div는 너비가 얼마고 높이가 얼마이니 여기에 위치해야 하고, 그 옆에 있는 요소는 밀려나야겠군" 과 같은 계산을 하는 단계. 이 과정은 CPU를 많이 사용하며 매우 비용이 큰 작업.
  1. Paint (Repaint): Layout 계산이 끝난 요소들에 색상, 이미지, 텍스트 등을 입혀 픽셀로 변환하는 단계.
  1. Composite: Paint 된 여러 개의 레이어(층)를 순서대로 합쳐서 최종 화면을 만들어냄. 이 과정은 주로 GPU가 담당하여 매우 빠름
 
문제의 코드:hover--box-height 값을 변경하여 결과적으로 height 속성을 바꾸고 있음. height는 요소의 실제 크기를 결정하므로, 이 값이 변하면 페이지 전체의 구조에 영향을 줄 수 있음
  • .box의 높이가 커지면 그 아래에 있던 다른 요소들은 모두 아래로 밀려나야 함
  • 브라우저는 이 변화를 감지하고 "요소 크기가 바뀌었네. 다른 요소들 위치를 전부 다시 계산해야겠다"라고 판단
  • 결국 애니메이션의 매 프레임마다 비싼 Layout(Reflow) 과정Paint 과정을 반복
  • 이는 CPU에 큰 부담을 주어 애니메이션이 뚝뚝 끊기는 현상을 유발하고 성능을 저하시킴
커스텀 변수 자체의 문제가 아니라, 그 변수가 Layout을 유발하는 height 속성에 적용되었기 때문에 성능 문제가 발생하는 것
 

올바른 해결책

.box { height: 100px; transform: scaleY(1); /* Y축(세로)으로 1배율 (원래 크기) */ transform-origin: top; /* 위쪽을 기준으로 커지도록 설정 */ transition: transform 0.3s ease; } .box:hover { transform: scaleY(2); /* Y축으로 2배율 (200px 처럼 보이게) */ }
올바른 해결책은 Layout 과정을 건너뛰고 Composite 단계에서 처리할 수 있는 속성을 사용하는 것. 대표적인 속성이 바로 transformopacity

transform이 더 빠른 이유

  • transform 속성은 요소의 Layout에 영향을 주지 않음. 브라우저는 transform이 적용된 요소를 별도의 레이어로 분리하여 처리
  • scaleY(2).box의 원래 height100px는 그대로 둔 채, 그래픽적으로만 세로로 2배 늘려 보여줌

 

6. Lighthouse가 체크하는 이유

Lighthouse = 웹사이트 성능 진단

의사: "웹사이트에서 애니메이션이 버벅거립니다" 진단: "CPU 애니메이션을 GPU 애니메이션으로 바꾸세요" 처방: "transform, opacity 사용하고 height, width 쓰지 마세요"

실제 Lighthouse 경고 메시지

"Avoid non-composited animations" "다음 속성들이 성능 문제를 일으킵니다:" - height (레이아웃 재계산 필요) - background-color (다시 그리기 필요) - --custom-variable (GPU에서 처리 불가)

 

7. 기존 문제 상황

개발자가 받던 혼란스러운 메시지

Before (기존): "Unsupported CSS Properties: height, --theme-color, width, --spacing" 개발자 반응: "height랑 --theme-color가 왜 같이 나오지?" "뭐가 다른 건지 모르겠어..."

이슈

GitHub Issue #14521: "커스텀 프로퍼티가 왜 일반 CSS랑 같이 나오는가, 이해가 안 된다. 분리해서 보여주라"

 

8. 해결 후

After (고친 후) "Unsupported CSS Properties: height, width" "Custom CSS properties cannot be animated on the compositor: --theme-color, --spacing" 개발자 "아! height, width는 transform으로 바꾸면 되겠네" "커스텀 변수는 원래 GPU에서 안 되는구나" "JavaScript로 변경하거나 다른 방법을 써야겠다"