개발 기술/사소하지만 놓치기 쉬운 개발 지식

CSS interpolate-size 기반 아코디언, JS보다 빠를까? 실측 성능 테스트

by GicoMomg 2025. 3. 15.

1. 들어가며

아코디언 애니메이션을 구현할 때 JavaScriptCSS 중 어떤 방식이 더 적합할까?

2024년 말에 CSS에 interpolate-size라는 새로운 실험 속성이 추가되었다.
이 속성은 heightwidth 같은 레이아웃 속성의 애니메이션을 보다 자연스럽게 처리할 수 있도록 도와준다고 한다.
그럼 JS 방식과 비교했을 때 성능적으로 어떤 장점이 있을까?

JS 기반 아코디언은 scrollHeight를 계산해 max-height를 동적으로 변경하는 방식으로 동작한다.

반면, interpolate-size를 사용하면 스크립트 연산 없이 애니메이션을 적용할 수 있다.
이론적으로 CSS 방식이 더 성능이 좋아야 하지만, 실제 성능 테스트 데이터를 확보해 확인해보고 싶었다.

그러나 수동 테스트만으로는 정확한 비교가 어려웠다. 그래서 Puppeteer 라이브러리 활용해 60개의 아코디언을 동시에 열고 닫는 테스트를 20회 반복했고,
Chrome Performance Trace를 이용해 측정값을 분석해보았다.

이번 시간에는 JS 기반 아코디언과 CSS 기반(interpolate-size) 아코디언의 성능 차이를 알아보자!




2. 아코디언 애니메이션 구현 방식

1) JavaScript 기반 아코디언

  • JavaScript 방식은 콘텐츠 영역의 scrollHeight를 이용해 max-height를 동적으로 업데이트한다.
  • 이 방법은 모든 브라우저에서 동작하는 장점이 있으나, 아코디언이 열릴 때마다 레이아웃 재계산(Reflow)이 발생하여 성능에 영향을 준다.
const accordionHeaderEl = document.querySelector('.accordion .accordion-header')

accordionHeaderEl.addEventListener('click', () => {
  const content = accordionHeaderEl.nextElementSibling;
  const isExpanded = content.style.maxHeight && content.style.maxHeight !== "0px";

  if (isExpanded) content.style.maxHeight = "0px";
  else content.style.maxHeight = content.scrollHeight + "px"; /* 스크롤 높이 사용 */
});

See the Pen js accordion example by KumJungMin (@kumjungmin) on CodePen.

 

 



2) CSS(interpolate-size) 기반 아코디언

(1) height:auto 애니메이션은 작동이 안된다.

  • 기존에는 heightwidth 속성을 auto로 변경하면 애니메이션이 작동하지 않았다.
  • 아래 예시는 아코디언이 열릴 때, 높이를 auto로 변경하는 방식이다.
  • transform을 추가했지만, height 값이 auto이기 때문에 애니메이션이 정상적으로 작동하지 않는다.
.accordion {
  width: 300px;
  border: 1px solid #ccc;
  margin-bottom: 10px;
}

.accordion .accordion-content {
  overflow: hidden;
  height: 0; /* 닫힌 상태 */
  transition: height 0.3s ease;
}

.accordion .accordion-content.open {
  height: auto; /* 열린 상태 */
}

See the Pen css height auto accordion example by KumJungMin (@kumjungmin) on CodePen.

 

 

 

(2) interpolate-size을 사용하면 애니메이션이 작동한다!

  • 하지만 interpolate-size 속성을 사용하면 브라우저가 자동으로 크기를 계산하기에 애니메이션이 작동된다!
.accordion {
  width: 300px;
  interpolate-size: allow-keywords; /* intrinsic size와 길이 값 간 애니메이션 활성화 */
  border: 1px solid #ccc;
  margin-bottom: 10px;
}

.accordion .accordion-content {
  overflow: hidden;
  height: 0; /* 닫힌 상태 */
  transition: height 0.3s ease;
}

.accordion .accordion-content.open {
  height: auto; /* 열린 상태 */
}

See the Pen interpolate-size accordion example by KumJungMin (@kumjungmin) on CodePen.

 

 

  • CSS 방식은 JS 연산에 의존하지 않아 구현이 간단하며, 선언적 스타일링이 가능하다는 장점이 있다.
  • 그러나 실험적 기능이므로 브라우저 호환성을 확인해야 한다.



3. 성능 테스트: 아코디언 60개를 동시에 열고 닫기

1) 테스트 방식

  • JS와 CSS 방식의 성능을 비교하기 위해, Puppeteer를 활용했다.
  • Puppeteer는 Headless Chrome을 제어할 수 있는 Node.js 라이브러리이다.
  • 스크립트를 통해 브라우저를 자동화하고 성능 측정을 수행할 수 있는데, 대규모 반복 테스트나 성능 분석에 매우 유용하다.

Puppeteer 로 테스트한 방법은 다음과 같다.

  1. HTML 페이지에 JavaScript와 CSS 방식의 아코디언 60개를 준비한다.
  2. Puppeteer를 사용해 60개 아코디언을 동시에 열고 닫는 동작을 일정한 시간 간격으로 20회 반복한다.
  3. Chrome의 Performance Trace를 통해 리플로우와 리페인트 등의 성능 지표를 기록하고 비교한다.
  4. 반복 실행한 결과의 평균 실행 시간을 도출한다.



2) 테스트 결과: 애니메이션 실행 시간

  • CPUThrottlingRate 값을 높이면 CPU 성능을 인위적으로 제한할 수 있어, 저사양 디바이스나 저속 환경을 가정한 성능 테스트가 가능하다.
  • 각 테스트 환경에서 애니메이션 실행 시간을 측정했으며, CPUThrottlingRate가 증가할수록 성능 차이가 어떻게 변하는지 확인했다.
`CPUThrottlingRate`별 애니메이션 속도 육안으로 보기
CPUThrottlingRate JS 방식                          CSS 방식                         
10(CPU 성능 1/10 감소) 344.51 ms 340.67 ms
50(CPU 성능 1/50 감소) 519.09 ms 534.02 ms
100(CPU 성능 1/100 감소) 846.68 ms 884.47 ms
200(CPU 성능 1/200 감소) 2179.30 ms 1882.13 ms
  • CPU 성능이 충분한 환경(CPUThrottlingRate 10)에서는 JS 방식과 CSS 방식 간 성능 차이가 거의 없었다.
  • 하지만 CPU 성능이 제한될수록(CPUThrottlingRate 200), JS 방식의 실행 시간이 CSS 방식보다 더 길어졌다.




3) 테스트 결과: 스타일 다시 계산 빈도와 횟수

(1) JS 기반 애니메이션의 성능

  • [개발자 도구/성능] > [상향식 뷰]는 각 함수가 CPU 사용 시간에서 차지하는 비율을 보여주는 분석 도구로,
  • 전체 성능에서 병목 현상이 발생하는 부분을 파악하는 데 유용하다.
  • JS 방식의 상향식 뷰를 살펴보면, 특정 연산이 성능을 크게 저하시키고 있음을 확인할 수 있다.

[ JS 상향식 뷰 ]
  • 요소의 scrollHeight를 구하는 연산(”get scrollHeight”)이 CPU 사용량의 22%를 차지하고 있다.
  • 해당 연산이 실행될 때마다 “스타일 다시 계산”이 동반되며, “스타일 다시 계산”의 비중이 38.8%로 매우 높았다.

 

[ 스타일 다시 계산 빈도 ]
  • JS 방식의 "스타일 다시 계산" 빈도도 같이 살펴보자. “스타일 다시 계산”이 일어나면 리플로우, 리페인트이 발생할 확률이 높다고 한다.
  • 그런데, JS 방식은 “스타일 다시 계산”이 반복적으로 발생하고 있다.
  • 그리고 Chrome DevTool을 살펴보면, "강제 실행된 리플로우는 성능 병목 현상이 될 수 있음" 이라는 경고 메시지가 표시된다.
  • 결국, JS 방식은 scrollHeight를 반복적으로 읽어들이면서 불필요한 리플로우 및 리페인트가 다수 발생하여 CPU 부하가 커진다고 볼 수 있다.

 

(2) CSS 기반 애니메이션의 성능

[ CSS 상향식 뷰 ]
  • CSS 방식에서는 "스타일 다시 계산"이 큰 비중을 차지하는 것처럼 보인다.
  • 그래서 JS 방식보다 성능이 나쁠 것이라고 생각할 수도 있다.

 

[ 스타일 다시 계산 빈도 ]
  • 하지만 “스타일 다시 계산” 발생 지점과 빈도를 보면, 실제로는 JS 방식보다 부담이 훨씬 적다는 걸 알 수 있다.

 

그럼 왜 스타일 다시 계산의 비중이 높았던 걸까?

  • CSS 방식은 애니메이션이 시작될 때 브라우저가 스타일을 한 번만 재계산하기 때문이다.
  • 이 과정에서 필요한 스타일 정보를 미리 정리하고, 이후 레이아웃과 페인트 작업을 최소화하여 애니메이션을 수행한다.
  • 즉, 상향식 뷰에서 "스타일 다시 계산" 비율이 높게 보일 수 있지만, 이는 초기 한 번의 계산일 뿐이고, 이후 불필요한 리플로우는 발생하지 않는다.
  • 결과적으로 CPU 부담은 JS 방식보다 훨씬 적다.




4. 마치며…

이번 시간에는 JavaScript 방식과 CSS(interpolate-size) 방식의 아코디언 애니메이션의 성능을 비교해보았다.

  • JS 방식의 문제점
    • scrollHeight를 참조하는 과정에서 강제 리플로우가 발생하며,
      그로 인해 스타일 다시 계산 → 레이아웃 재계산 → 리페인트가 반복적으로 실행된다.
    • 특히 아코디언 개수가 많아질수록 연산 부하가 누적되면서 성능이 점점 저하된다.
  • CSS(interpolate-size) 방식의 장점
    • 초기에 한 번만 스타일을 재계산한 뒤, 이후 레이아웃과 페인트 작업을 최소화하며 애니메이션을 처리한다.
    • 실행 시간 자체는 JS 방식과 큰 차이가 없지만, CPU 점유율과 렌더링 최적화 면에서는 더 효율적이다.
    • 특히 CPU 성능이 제한된 환경(CPU Throttling)에서도 안정적인 성능을 유지한다.

결론적으로, CSS(interpolate-size) 방식은 선언적으로 구현할 수 있고, 성능 최적화도 더 수월하다.

물론 실제 유저의 환경이 극단적이지 않아 이 차이가 실제 동작에 큰 영향을 주지 않을 수 있다.
따라서, 서비스를 이용하는 유저의 비율과 그들의 환경, 브라우저 호환성을 고려해 방법을 선택하는 게 좋다.



반응형

댓글