고성능 CSS 애니메이션을 만드는 방법

이 가이드에서는 고성능 CSS 애니메이션을 만드는 방법을 알아봅니다.

이러한 권장사항의 이론은 일부 애니메이션이 느린 이유는 무엇인가요?를 참고하세요.

브라우저 호환성

이 가이드에서 권장하는 모든 CSS 속성은 브라우저 간 지원이 우수합니다.

transform

Browser Support

  • Chrome: 36.
  • Edge: 12.
  • Firefox: 16.
  • Safari: 9.

Source

opacity

Browser Support

  • Chrome: 1.
  • Edge: 12.
  • Firefox: 1.
  • Safari: 2.

Source

will-change

Browser Support

  • Chrome: 36.
  • Edge: 79.
  • Firefox: 36.
  • Safari: 9.1.

Source

요소 이동

요소를 이동하려면 transform 속성의 translate 또는 rotation 키워드 값을 사용합니다.

예를 들어 항목을 뷰로 슬라이드하려면 translate를 사용합니다.

.animate {
  animation: slide-in 0.7s both;
}

@keyframes slide-in {
  0% {
    transform: translateY(-1000px);
  }
  100% {
    transform: translateY(0);
  }
}

rotate를 사용하여 요소를 회전합니다. 다음 예시에서는 요소를 360도 회전합니다.

.animate {
  animation: rotate 0.7s ease-in-out both;
}

@keyframes rotate {
  0% {
    transform: rotate(0);
  }
  100% {
    transform: rotate(360deg);
  }
}

요소 크기 조정

요소의 크기를 조정하려면 transform 속성의 scale 키워드 값을 사용합니다.

.animate {
  animation: scale 1.5s both;
}

@keyframes scale {
  50% {
    transform: scale(0.5);
  }
  100% {
    transform: scale(1);
  }
}

요소의 공개 상태 변경

요소를 표시하거나 숨기려면 opacity을 사용합니다.

.animate {
  animation: opacity 2.5s both;
}

@keyframes opacity {
  0% {
    opacity: 1;
  }
  50% {
    opacity: 0;
  }
  100% {
    opacity: 1;
  }
}

레이아웃이나 페인트를 트리거하는 속성 피하기

애니메이션에 CSS 속성 (transformopacity 제외)을 사용하기 전에 렌더링 파이프라인에 미치는 속성의 영향을 확인하세요. 레이아웃이나 페인트를 트리거하는 속성은 꼭 필요한 경우가 아니면 피하세요.

레이어 생성을 강제 적용

일부 애니메이션이 느린 이유는 무엇인가요?에 설명된 대로 요소를 새 레이어에 배치하면 브라우저가 나머지 레이아웃을 다시 그릴 필요 없이 요소를 다시 그릴 수 있습니다.

브라우저는 일반적으로 새 레이어에 배치해야 하는 항목에 관해 적절한 결정을 내릴 수 있지만 will-change 속성을 사용하여 레이어 생성을 수동으로 강제할 수 있습니다. 이름에서 알 수 있듯이 이 속성은 브라우저에 이 요소가 어떤 방식으로든 변경될 것이라고 알려줍니다.

CSS에서는 모든 선택기에 will-change를 적용할 수 있습니다.

body > .sidebar {
  will-change: transform;
}

하지만 사양에서는 항상 변경될 요소에만 이를 추가해야 한다고 제안합니다. 예를 들어 사용자가 슬라이드하여 표시하거나 숨길 수 있는 사이드바에 사용할 수 있습니다. 요소가 자주 변경되지 않는 경우 변경이 발생할 가능성이 있을 때 JavaScript를 사용하여 will-change를 적용합니다. 브라우저가 필요한 최적화를 실행할 수 있도록 충분한 시간을 주고 변경이 중지되면 속성을 삭제해야 합니다.

will-change를 지원하지 않는 브라우저에서 레이어 생성을 강제하려면 transform: translateZ(0)을 설정하면 됩니다.

느리거나 글리치한 애니메이션 디버그

Chrome DevTools와 Firefox DevTools를 사용하면 애니메이션이 느리거나 글리치 현상이 발생하는 이유를 파악할 수 있습니다.

애니메이션이 레이아웃을 트리거하는지 확인

transform 이외의 요소를 사용하여 요소를 이동하는 애니메이션은 느릴 수 있습니다. 다음 예에서는 transform를 사용하는 애니메이션과 topleft를 사용하는 애니메이션을 비교합니다.

금지사항
.box {
  position: absolute;
  top: 10px;
  left: 10px;
  animation: move 3s ease infinite;
}

@keyframes move {
  50% {
     top: calc(90vh - 160px);
     left: calc(90vw - 200px);
  }
}
권장사항
.box {
  position: absolute;
  top: 10px;
  left: 10px;
  animation: move 3s ease infinite;
}

@keyframes move {
  50% {
     transform: translate(calc(90vw - 200px), calc(90vh - 160px));
  }
}

다음 두 예에서 이를 테스트하고 DevTools를 사용하여 성능을 살펴볼 수 있습니다.

Chrome DevTools

  1. 성능 패널을 엽니다.
  2. 애니메이션이 진행되는 동안 런타임 성능을 기록합니다.
  3. 요약 탭을 검사합니다.

요약 탭에 렌더링 값이 0이 아닌 경우 애니메이션으로 인해 브라우저에서 레이아웃 작업을 실행하고 있을 수 있습니다.

요약 패널에 렌더링 37ms, 페인팅 79ms가 표시됩니다.
animation-with-top-left 예시로 인해 렌더링 작업이 발생합니다.
요약 패널에 렌더링 및 페인팅 값이 0으로 표시됩니다.
animation-with-transform 예시에서는 렌더링 작업이 발생하지 않습니다.

Firefox DevTools

Firefox DevTools의 폭포를 사용하면 브라우저가 시간을 어디에 사용하는지 파악할 수 있습니다.

  1. 성능 패널을 엽니다.
  2. 애니메이션이 진행되는 동안 성능 녹화를 시작합니다.
  3. 녹화를 중지하고 폭포 탭을 검사합니다.

Recalculate Style 항목이 표시되면 브라우저가 애니메이션을 렌더링하기 위해 렌더링 워터폴의 시작 부분으로 돌아가야 합니다.

프레임 드롭 확인

  1. Chrome DevTools에서 렌더링을 엽니다.
  2. FPS 미터 체크박스를 사용 설정합니다.
  3. 애니메이션이 실행되는 동안 값을 확인합니다.

FPS 미터 UI 상단의 프레임 라벨에 주의하세요. 50% 1 (938 m) dropped of 1878과 같은 값이 표시됩니다. 고성능 애니메이션의 비율은 99%와 같이 높습니다. 즉, 삭제되는 프레임이 거의 없으며 애니메이션이 매끄럽게 표시됩니다.

FPS 측정기에 프레임의 50% 가 삭제된 것으로 표시됨
animation-with-top-left 예시에서는 프레임의 50% 가 삭제됩니다.
FPS 측정기에는 프레임이 1% 만 삭제된 것으로 표시됩니다.
animation-with-transform 예시에서는 프레임의 1% 만 삭제됩니다.

애니메이션이 페인트를 트리거하는지 확인

일부 속성은 브라우저에서 페인트하는 데 다른 속성보다 비용이 더 많이 듭니다. 예를 들어 흐림 효과 (예: 그림자)가 포함된 항목은 빨간색 상자를 그리는 것보다 렌더링하는 데 시간이 더 오래 걸립니다. 이러한 차이는 CSS에서 항상 명확하지는 않지만 브라우저 DevTools를 사용하면 다시 칠해야 하는 영역과 기타 페인팅 관련 성능 문제를 파악할 수 있습니다.

Chrome DevTools

  1. Chrome DevTools에서 렌더링을 엽니다.
  2. 페인트 깜박임을 선택합니다.
  3. 화면에서 포인터를 이동합니다.
다시 칠해질 것임을 보여주기 위해 녹색으로 강조 표시된 UI 요소
Google 지도의 이 예에서는 요소가 다시 그려지는 것을 확인할 수 있습니다.

전체 화면이 깜박이거나 변경되지 않아야 하는 영역이 강조 표시되면 추가로 조사하세요.

특정 속성으로 인해 페인팅 관련 성능 문제가 발생하는지 확인해야 하는 경우 Chrome DevTools의 페인트 프로파일러가 도움이 될 수 있습니다.

Firefox DevTools

  1. 설정을 열고 페인트 깜박임 전환을 위한 도구 상자 버튼을 추가합니다.
  2. 검사하려는 페이지에서 버튼을 전환하고 마우스를 이동하거나 스크롤하여 강조 표시된 영역을 확인합니다.

컴포지트 단계에서 애니메이션 적용

가능한 경우 애니메이션을 opacitytransform로 제한하여 렌더링 경로의 컴포지션 단계에서 애니메이션을 유지하세요. DevTools를 사용하여 경로의 어느 단계가 애니메이션의 영향을 받는지 확인합니다.

페인트 프로파일러를 사용하여 특히 비용이 많이 드는 페인트 작업이 있는지 확인합니다. 문제가 발견되면 다른 CSS 속성이 더 나은 성능으로 동일한 디자인을 제공하는지 확인하세요.

will-change 속성은 성능 문제가 발생하는 경우에만 신중하게 사용하세요.