웹 성능의 숨은 적: Reflow와 Repaint를 유발하는 최악의 CSS 습관
1. 브라우저는 어떻게 화면을 그릴까?
웹사이트의 로딩 속도가 느리다면 단순히 서버의 문제만이 아닐 확률이 높습니다. 브라우저가 HTML과 CSS를 받아 화면에 출력하는 '렌더링 파이프라인' 단계에서 병목 현상이 발생하기 때문입니다. 특히 자바스크립트나 CSS를 통해 요소를 변경할 때 발생하는 Reflow(리플로우)와 Repaint(리페인트)는 성능에 치명적인 영향을 미칩니다.
2. Reflow vs Repaint: 개념의 핵심
- Reflow (Layout): 생성된 DOM 노드의 레이아웃 수치(너비, 높이, 위치 등) 변경 시 영향받는 모든 노드의 수치를 재계산하고 렌더 트리를 재생성하는 과정입니다.
- Repaint (Paint): 레이아웃에는 영향이 없지만, 가시성(색상, 테두리 등)이 변했을 때 화면을 다시 그리는 과정입니다. 리플로우보다는 가볍지만 여전히 비용이 발생합니다.
3. 성능을 갉아먹는 최악의 CSS 습관 5가지
① 인라인 스타일(Inline Style) 남용
JavaScript로 element.style.width = '100px';와 같이 스타일을 직접 조작하면 수정을 가할 때마다 리플로우가 발생합니다. 클래스를 미리 정의하고 classList를 통해 한 번에 교체하는 것이 훨씬 효율적입니다.
② 'Table' 레이아웃 사용
테이블 레이아웃은 데이터 표시용이지 페이지 전체 구조용이 아닙니다. 테이블은 작은 변경 사항만 있어도 내부의 모든 셀이 레이아웃을 다시 계산하게 만드는 특성이 있어 리플로우 연산량이 엄청납니다.
③ 애니메이션 구현 시 Left, Top 사용
요소를 이동시킬 때 left나 top 속성을 사용하면 매 프레임마다 리플로우가 발생합니다. 대신 GPU 가속을 활용하는 transform: translate()를 사용해야 합니다.
④ 불필요한 복잡한 CSS 선택자
브라우저는 CSS 선택자를 오른쪽에서 왼쪽으로 읽습니다. div > ul > li > a와 같은 복잡한 선택자는 매칭 과정에서 불필요한 연산을 유도합니다. 가급적 클래스 하나로 끝내는 것이 최선입니다.
⑤ 레이아웃 스래싱(Layout Thrashing) 유발
반복문 내에서 offsetHeight 같은 수치를 읽고 동시에 수정하는 행위는 브라우저의 렌더링 큐를 강제로 비우게 하여 성능을 극단적으로 저하시킵니다.
4. 성능 최적화 코드 예시
/* 나쁜 예: 매번 리플로우 발생 */
.box {
position: absolute;
left: 10px;
top: 10px;
transition: left 0.5s;
}
/* 좋은 예: 리페인트만 발생 (GPU 가속 활용) */
.box {
transform: translate(10px, 10px);
transition: transform 0.5s;
will-change: transform;
}
댓글
댓글 쓰기