JavaScript는 시각적 변경을 트리거하는 경우가 많습니다. 스타일 조작을 통해 직접 변경하는 경우도 있고, 데이터 검색이나 정렬과 같이 시각적 변경사항을 초래하는 계산을 통해 변경하는 경우도 있습니다. 타이밍이 잘못되거나 장시간 실행되는 JavaScript는 성능 문제의 일반적인 원인이 될 수 있으므로 가능한 경우 영향을 최소화해야 합니다.
스타일 계산
요소를 추가 및 삭제하거나 속성, 클래스를 변경하거나 애니메이션을 재생하여 DOM을 변경하면 브라우저에서 요소 스타일을 다시 계산하고 대부분의 경우 페이지의 일부 또는 전체 레이아웃을 다시 계산합니다. 이 과정을 스타일 계산이라고 합니다.
브라우저는 일치하는 선택기 집합을 만들어 특정 요소에 적용할 클래스, 가상 선택기, ID를 결정하여 스타일 계산을 시작합니다. 그런 다음 일치하는 선택기의 스타일 규칙을 처리하고 요소의 최종 스타일을 파악합니다.
상호작용 지연 시간에서 스타일 다시 계산의 역할
다음 페인트에 대한 상호작용 (INP)은 사용자 입력에 대한 페이지의 전반적인 응답성을 평가하는 사용자 중심 런타임 성능 측정항목입니다. 사용자가 페이지와 상호작용하는 시점부터 브라우저가 사용자 인터페이스의 상응하는 시각적 업데이트를 보여주는 다음 프레임을 페인트할 때까지의 상호작용 지연 시간을 측정합니다.
상호작용의 중요한 구성요소는 다음 프레임을 페인트하는 데 걸리는 시간입니다. 다음 프레임을 표시하기 위해 실행되는 렌더링 작업은 레이아웃, 페인트, 컴포지션 작업 직전에 발생하는 페이지 스타일 계산을 비롯한 여러 부분으로 구성됩니다. 이 가이드에서는 스타일 계산 비용에 중점을 두지만 상호작용의 총 렌더링 시간 중 일부를 줄이면 총 지연 시간도 줄어듭니다.
선택기의 복잡성 줄이기
CSS 선택기를 단순화하면 페이지의 스타일 계산 속도를 높일 수 있습니다. 가장 간단한 선택자는 클래스 이름만으로 CSS의 요소를 참조합니다.
.title {
/* styles */
}
하지만 프로젝트가 커짐에 따라 더 복잡한 CSS가 필요할 수 있으며 다음과 같은 선택기가 생성될 수 있습니다.
.box:nth-last-child(-n+1) .title {
/* styles */
}
이러한 스타일이 페이지에 적용되는 방식을 확인하려면 브라우저는 'title
클래스의 요소이고 상위 요소의 minus-nth-plus-1 하위 요소이며 상위 요소의 클래스가 box
인가요? 브라우저에서 이를 파악하는 데 다소 시간이 걸릴 수 있습니다. 이를 간소화하려면 선택기를 더 구체적인 클래스 이름으로 변경하면 됩니다.
.final-box-title {
/* styles */
}
이러한 대체 클래스 이름은 어색해 보일 수 있지만 브라우저의 작업을 훨씬 간단하게 만듭니다. 예를 들어 이전 버전에서는 브라우저가 요소가 유형의 마지막 요소인지 알기 위해 먼저 다른 모든 요소에 관한 모든 정보를 알아야 하며, 그다음에 그 뒤에 오는 요소가 nth-last-child
일 수 있는지 확인할 수 있습니다. 이는 클래스 이름만을 기준으로 선택기를 요소에 일치시키는 것보다 훨씬 더 많은 계산 비용이 들 수 있습니다.
스타일이 지정되는 요소 수 줄이기
또 다른 성능 고려사항은 선택자 복잡성보다 더 중요한 경우가 많으며, 요소가 변경될 때 실행해야 하는 작업의 양입니다.
일반적으로 계산된 요소 스타일을 계산하는 최악의 경우 비용은 요소 수와 선택자 수를 곱한 값입니다. 브라우저는 일치하는지 확인하기 위해 각 요소를 모든 스타일과 한 번 이상 비교해야 하기 때문입니다.
스타일 계산은 전체 페이지를 무효화하는 대신 몇 가지 요소를 직접 타겟팅할 수 있습니다. 최신 브라우저에서는 브라우저가 변경사항이 영향을 줄 수 있는 모든 요소를 항상 확인할 필요가 없으므로 이 문제가 덜 발생하는 경향이 있습니다. 반면 이전 버전의 브라우저는 이러한 작업에 최적화되어 있지 않을 수 있습니다. 가능하면 무효화된 요소 수를 줄여야 합니다.
스타일 다시 계산 비용 측정
브라우저에서 스타일 재계산 비용을 측정하는 방법에는 여러 가지가 있습니다. 각 방법은 개발 환경의 브라우저에서 측정할지 또는 웹사이트에서 실제 사용자가 이 프로세스를 실행하는 데 걸리는 시간을 측정할지에 따라 다릅니다.
Chrome DevTools에서 스타일 재계산 비용 측정
스타일 재계산 비용을 측정하는 한 가지 방법은 Chrome DevTools의 성능 패널을 사용하는 것입니다. 시작하려면 다음 단계를 따르세요.
- DevTools를 엽니다.
- 실적 탭으로 이동합니다.
- 선택기 통계 체크박스를 선택합니다 (선택사항).
- 녹음을 클릭합니다.
- 페이지와 상호작용합니다.
녹화를 중지하면 다음과 같은 이미지가 표시됩니다.

상단의 스트립은 초당 프레임도 표시하는 소형 플레임 차트입니다. 활동이 스트립 하단에 가까울수록 브라우저에서 프레임을 더 빠르게 페인트합니다. Flame 그래프가 상단에서 평평해지고 그 위에 빨간색 막대가 표시되면 프레임이 장시간 실행되는 작업이 있는 것입니다.

스크롤과 같은 상호작용 중에 장기 실행 프레임이 있는지 자세히 살펴볼 가치가 있습니다. 큰 보라색 블록이 표시되면 활동을 확대하고 스타일 다시 계산이라는 라벨이 지정된 작업을 선택하여 비용이 많이 들 수 있는 스타일 다시 계산 작업에 관한 자세한 정보를 확인합니다.

이벤트를 클릭하면 호출 스택이 표시됩니다. 렌더링 작업이 사용자 상호작용으로 인해 발생한 경우 스타일 변경을 트리거한 JavaScript를 호출합니다. 변경사항이 영향을 미치는 요소 수(이 경우 900개가 조금 넘음)와 스타일 계산에 걸린 시간도 표시됩니다. 이 정보를 사용하여 코드에서 해결 방법을 찾을 수 있습니다.
트레이스를 실행하기 전에 성능 패널 설정에서 선택기 통계 체크박스를 선택한 경우 트레이스의 하단 패널에 동일한 이름의 탭이 추가로 표시됩니다.

이 패널은 각 선택자의 상대적 비용에 관한 유용한 데이터를 제공하므로 비용이 많이 드는 CSS 선택자를 식별할 수 있습니다.
자세한 내용은 CSS 선택자 통계 문서를 참고하세요.
실제 사용자의 스타일 재계산 비용 측정
웹사이트의 실제 사용자에게 스타일 재계산이 발생하는 데 걸리는 시간을 알고 싶다면 Long Animation Frames API를 사용하세요. 이 API의 데이터는 스타일 재계산 시간을 포함하여 web-vitals
JavaScript 라이브러리에 추가되었습니다.
상호작용의 프레젠테이션 지연이 페이지의 INP에 가장 큰 영향을 미치는 것으로 의심되는 경우 페이지의 스타일을 다시 계산하는 데 걸리는 시간을 파악해야 합니다. 자세한 내용은 필드에서 스타일 재계산 시간을 측정하는 방법을 참고하세요.