📑 목차
웹 페이지를 개발하고 최적화하는 과정에서 'Reflow'와 'Repaint'라는 용어를 자주 듣게 됩니다. 이들은 웹 성능에 직접적인 영향을 미치는 중요한 개념으로, 웹 페이지가 사용자에게 얼마나 빠르고 부드럽게 보이는지를 결정합니다. 이 가이드에서는 Reflow와 Repaint가 무엇인지, 언제 발생하는지, 그리고 웹 페이지의 성능을 최적화하기 위해 어떻게 최소화할 수 있는지에 대해 자세히 알아보겠습니다.
웹 성능의 핵심 Reflow와 Repaint 이해하기
브라우저는 웹 페이지를 화면에 표시하기 위해 여러 단계를 거칩니다. 이 과정은 크게 다음과 같습니다.
-
- DOM (Document Object Model) 트리 생성 HTML을 파싱하여 DOM 트리를 만듭니다.
-
- CSSOM (CSS Object Model) 트리 생성 CSS를 파싱하여 CSSOM 트리를 만듭니다.
- 렌더 트리 (Render Tree) 생성 DOM 트리와 CSSOM 트리를 결합하여 화면에 표시될 요소들만 포함하는 렌더 트리를 생성합니다. 이 트리는 각 요소의 시각적 정보를 포함합니다.
- 레이아웃 (Layout 또는 Reflow) 렌더 트리의 각 요소가 화면의 어디에, 어떤 크기로 배치될지 계산합니다. 모든 요소의 위치와 크기가 결정되는 단계입니다.
- 페인트 (Paint 또는 Repaint) 레이아웃 단계에서 계산된 정보를 바탕으로 각 요소의 시각적인 부분(색상, 배경, 테두리 등)을 실제 픽셀로 변환하여 화면에 그리는 단계입니다.
- 합성 (Compositing) 그려진 여러 레이어를 최종적으로 합쳐 화면에 표시합니다.
여기서 우리가 집중할 부분은 바로 '레이아웃'과 '페인트' 단계입니다.
Reflow 레이아웃이란 무엇인가요
Reflow는 '레이아웃'이라고도 불리며, 웹 페이지의 특정 요소가 변경되어 해당 요소뿐만 아니라 주변 또는 전체 레이아웃에 영향을 미칠 때 발생합니다. 즉, 요소의 크기나 위치, DOM 구조 등이 변경되어 브라우저가 모든 요소의 위치와 크기를 다시 계산해야 하는 과정입니다. Reflow는 전체 렌더 트리의 재구성으로 이어질 수 있으며, 이는 매우 비용이 많이 드는 작업입니다. 한 번의 Reflow는 필연적으로 Repaint를 유발합니다.
Repaint 페인트란 무엇인가요
Repaint는 '페인트'라고도 불리며, 요소의 시각적인 스타일(색상, 배경, 그림자 등)만 변경되고 레이아웃에는 영향을 주지 않을 때 발생합니다. 브라우저는 이미 계산된 레이아웃 정보를 사용하여 변경된 요소의 픽셀만 다시 그립니다. Reflow보다 비용이 적게 들지만, 너무 자주 발생하면 역시 성능 저하의 원인이 됩니다.
왜 Reflow와 Repaint가 중요한가요
Reflow와 Repaint는 웹 페이지의 성능을 저하시키는 주요 원인입니다. 특히 Reflow는 브라우저가 많은 계산을 다시 해야 하므로, 페이지가 버벅거리거나 사용자 입력에 대한 반응이 느려지는 현상(렉)을 유발할 수 있습니다. 이는 사용자 경험을 크게 해치며, 모바일 환경에서는 배터리 소모 증가로도 이어질 수 있습니다. 따라서 이들을 최소화하는 것은 웹 성능 최적화의 핵심 과제 중 하나입니다.
Reflow와 Repaint가 발생하는 구체적인 조건들
어떤 상황에서 Reflow와 Repaint가 발생하는지 정확히 이해하는 것이 최적화의 첫걸음입니다. 다음은 주요 발생 조건들입니다.
Reflow를 유발하는 주요 요인
-
- DOM 구조 변경 요소를 추가, 삭제하거나 숨기거나 보이게 할 때 (display: none은 Reflow를 유발하지만, visibility: hidden은 Reflow를 유발하지 않습니다).
- 레이아웃 관련 CSS 속성 변경 width, height, margin, padding, border, position (top, left 등), float, clear, text-align, line-height, font-size, overflow, display, flex, grid 등 레이아웃에 영향을 주는 속성을 변경할 때 발생합니다.
- 창 크기 변경 브라우저 창의 크기를 조절할 때 페이지 전체의 레이아웃이 다시 계산됩니다.
- 콘텐츠 변경 이미지의 크기가 변경되거나, 텍스트 내용이 변경되어 요소의 크기가 달라질 때 발생합니다.
- CSS 애니메이션 width나 height와 같이 레이아웃에 영향을 주는 속성을 애니메이션 할 때 Reflow가 발생합니다.
- 스크롤바 스크롤바의 유무나 크기가 변경될 때 (브라우저마다 다를 수 있습니다).
- 특정 JavaScript 작업 JavaScript에서 offsetTop, offsetLeft, offsetWidth, offsetHeight, scrollTop, scrollLeft, scrollWidth, scrollHeight, clientTop, clientLeft, clientWidth, clientHeight, getComputedStyle() 등 레이아웃 정보를 요청하는 속성에 접근할 때 브라우저는 최신 레이아웃을 계산해야 하므로 Reflow가 발생합니다. 이를 '강제 동기 레이아웃'이라고 합니다.
Repaint만 유발하는 요인
- 색상 변경 color, background-color, border-color, box-shadow, text-shadow 등 색상 관련 속성을 변경할 때 발생합니다.
- 시각적 속성 변경 opacity, visibility (hidden/visible), outline 등 시각적인 표현만 변경하고 레이아웃에 영향을 주지 않는 속성을 변경할 때 발생합니다.
- Transform (일부) translate, rotate, scale 등 레이아웃에 영향을 주지 않는 3D 변환 속성을 사용할 때 발생합니다.
- Filters blur, brightness 등 CSS 필터 속성을 사용할 때 발생합니다.
성능 최적화를 위한 Reflow와 Repaint 최소화 전략
이제 Reflow와 Repaint를 줄여 웹 성능을 향상시키는 구체적인 전략들을 살펴보겠습니다.
Reflow 최소화 핵심 전략
- DOM 변경 최소화 여러 DOM 변경을 한 번에 처리하세요.
- DocumentFragment를 사용하여 여러 요소를 메모리에서 조작한 후, 최종적으로 DOM에 한 번만 추가합니다.
- display: none으로 요소를 숨긴 후 여러 변경을 수행하고, 다시 display: block으로 보이게 합니다. 이렇게 하면 숨겨진 상태에서는 Reflow가 발생하지 않습니다.
- 개별 속성 변경 대신 CSS 클래스를 토글하여 스타일을 변경합니다. 클래스 변경은 한 번의 Reflow로 여러 속성을 변경할 수 있습니다.
- 레이아웃에 영향 없는 CSS 속성 활용 애니메이션이나 동적인 효과에는 transform (특히 translate, scale, rotate)과 opacity를 우선적으로 사용합니다. 이들은 Reflow를 유발하지 않고 Repaint나 Composite 단계에서 처리되어 부드러운 애니메이션을 만듭니다.
- 강제 동기 레이아웃 피하기 JavaScript에서 offsetWidth, getComputedStyle() 등 레이아웃 정보를 요청하는 속성에 접근하기 전에 DOM 변경을 완료하거나, 이전에 계산된 값을 캐싱하여 사용합니다. 한 프레임 내에서 DOM 변경과 레이아웃 정보 요청을 번갈아 가며 하는 것은 피해야 합니다.
- CSS 애니메이션 최적화 will-change 속성을 사용하여 브라우저에게 해당 요소의 속성이 변경될 것임을 미리 알려주어 최적화를 유도할 수 있습니다. transform이나 opacity와 같은 속성에 will-change를 적용하면 GPU 가속을 더욱 효과적으로 활용할 수 있습니다.
- position: absolute 또는 position: fixed 활용 문서의 흐름에서 요소를 제거하여 주변 요소의 Reflow에 미치는 영향을 최소화합니다. 특히 동적으로 움직이거나 크기가 변하는 요소에 유용합니다.
- Flexbox와 Grid Layout 신중하게 사용 강력한 레이아웃 도구이지만, 복잡한 구조나 빈번한 변경이 있는 경우 Reflow 비용이 높을 수 있습니다. 꼭 필요한 경우에만 사용하고 구조를 단순하게 유지하는 것이 좋습니다.
Repaint 최소화 전략
- GPU 가속 활용 transform (특히 3D), opacity, filter 등의 속성은 GPU를 사용하여 Composite 단계에서 처리될 수 있어 Repaint를 줄이고 부드러운 애니메이션을 만듭니다. will-change 속성을 함께 사용하면 좋습니다.
- 레이어 분리 특정 요소를 독립적인 합성 레이어(compositing layer)로 분리하여 해당 요소만 Repaint/Composite되도록 합니다. transform: translateZ(0) (혹은 translate3d(0,0,0))이나 will-change: transform 등을 사용해 레이어 분리를 유도할 수 있습니다. 이는 다른 요소의 변경이 해당 레이어에 영향을 주지 않게 하여 전체 페이지의 Repaint를 줄이는 데 도움이 됩니다.
실생활에서의 활용 방법과 유용한 팁
- 애니메이션 구현 시 항상 transform과 opacity를 우선적으로 고려하세요. 예를 들어, 요소의 위치를 이동시키려면 left/top 대신 transform: translateX()/translateY()를 사용하세요.
- 요소 숨기기 요소를 완전히 숨길 때는 display: none 대신 visibility: hidden 또는 opacity: 0을 고려해보세요. visibility: hidden은 Reflow를 유발하지 않으며, opacity: 0은 Repaint만 유발하고 GPU 가속을 받을 수 있습니다.
- CSS class 기반 스타일 변경 JavaScript로 개별 CSS 속성을 직접 변경하는 대신, 미리 정의된 CSS 클래스를 추가하거나 제거하여 스타일을 변경하는 것이 효율적입니다. 이는 브라우저가 변경 사항을 한 번에 처리할 수 있게 돕습니다.
- 이미지 로딩 이미지의 width와 height를 HTML 태그나 CSS에서 미리 지정해주세요. 이렇게 하면 이미지가 로드될 때마다 레이아웃이 변경되어 Reflow가 발생하는 것을 방지할 수 있습니다.
- 웹 폰트 로딩 웹 폰트가 로드될 때 텍스트의 크기가 변경되어 Reflow가 발생할 수 있습니다. font-display 속성을 사용하여 폰트 로딩 전략을 관리하고, @font-face에 size-adjust나 line-gap-override 같은 속성을 활용하여 레이아웃 변경을 최소화할 수 있습니다.
- 개발자 도구 활용 Chrome DevTools의 Performance 탭을 적극적으로 활용하세요. 이곳에서 Reflow와 Repaint가 언제, 어디서, 얼마나 오래 발생하는지 시각적으로 확인할 수 있습니다. 이를 통해 성능 병목 지점을 정확히 파악하고 개선할 수 있습니다.
흔한 오해와 사실 관계
Reflow와 Repaint에 대한 몇 가지 흔한 오해를 바로잡아 보겠습니다.
오해사실 관계모든 CSS 애니메이션은 Reflow를 유발한다.transform (특히 translate, scale, rotate)과 opacity와 같은 속성을 사용하는 애니메이션은 Reflow를 유발하지 않고 Repaint나 Composite 단계에서 처리됩니다. 레이아웃에 영향을 주는 width, height, margin 등의 속성을 애니메이션 할 때 Reflow가 발생합니다.visibility: hidden은 Reflow를 유발한다.visibility: hidden은 요소를 숨기지만, 그 공간은 여전히 차지하므로 레이아웃 변경(Reflow)을 유발하지 않습니다. 단지 시각적으로만 사라지므로 Repaint는 발생합니다. display: none은 요소의 공간 자체를 없애므로 Reflow를 유발합니다.position: absolute 또는 position: fixed 요소는 Reflow를 전혀 유발하지 않는다. 이들 요소는 문서 흐름에서 제거되므로, 이들 요소의 변경이 주변 요소의 Reflow를 유발하지는 않습니다. 하지만 해당 요소 자체의 width, height, top, left 등의 속성 변경은 해당 요소에 대한 Reflow를 유발할 수 있습니다. Reflow는 항상 나쁘다. Reflow는 브라우저가 요소를 올바르게 배치하기 위한 필수적인 과정입니다. 문제는 불필요하게 자주 발생하거나, 광범위한 영역에 걸쳐 발생할 때 성능 저하를 일으킨다는 점입니다.
전문가의 조언 및 자주 묻는 질문
전문가 조언
- "성능 최적화는 미신이 아니다. 항상 측정하고 분석하라." - 추측에 의존하기보다 개발자 도구를 통해 실제 성능 데이터를 확인하는 것이 중요합니다. 어디서 Reflow/Repaint가 발생하는지 정확히 파악해야 합니다.
- "작은 Reflow/Repaint는 괜찮다. 반복적이고 광범위한 것이 문제다." - 모든 Reflow/Repaint를 없앨 수는 없습니다. 핵심은 불필요하게 자주, 그리고 넓은 영역에 걸쳐 발생하는 것을 줄이는 것입니다.
- "GPU 가속은 만능이 아니다. 남용하면 오히려 성능 저하를 일으킬 수 있다." - GPU 가속은 특정 상황에서 매우 효과적이지만, 너무 많은 요소를 독립적인 레이어로 만들면 오히려 메모리 사용량이 증가하고 브라우저에 부담을 줄 수 있습니다. 신중하게 사용해야 합니다.
자주 묻는 질문
Q1: Reflow와 Repaint 중 어느 것이 더 비용이 많이 드나요?
A1: Reflow가 훨씬 더 비용이 많이 듭니다. Reflow는 요소의 위치와 크기를 재계산해야 하므로 복잡한 과정이며, 종종 전체 페이지의 레이아웃에 영향을 미칩니다. 반면 Repaint는 이미 계산된 레이아웃 위에 픽셀만 다시 그리는 작업이므로 상대적으로 가볍습니다.
Q2: 모든 브라우저에서 Reflow/Repaint 동작이 동일한가요?
A2: 기본적인 원리는 같지만, 브라우저 엔진(예: Chromium 기반, Gecko, WebKit 등)마다 최적화 방식이나 구현 디테일이 다를 수 있습니다. 따라서 특정 브라우저에서 잘 작동하는 최적화가 다른 브라우저에서는 다르게 동작할 수도 있습니다. 항상 다양한 브라우저에서 테스트하는 것이 좋습니다.
Q3: JavaScript로 CSS 속성을 변경하는 것이 더 안 좋은가요?
A3: JavaScript로 직접 CSS 속성을 변경하든, CSS 클래스를 토글하든, 브라우저가 수행하는 Reflow/Repaint 자체는 동일합니다. 문제는 JavaScript로 DOM에 접근하여 레이아웃 정보를 강제로 요청하는 패턴(강제 동기 레이아웃)이 Reflow를 유발하기 쉽다는 점입니다. 여러 DOM 변경을 한 번의 Repaint/Reflow로 묶어서 처리하는 것이 중요합니다.
비용 효율적인 활용 방법
최적화는 항상 자원(시간, 개발 노력 등) 대비 효과를 고려해야 합니다. 다음은 비용 효율적인 최적화 방법입니다.
- 불필요한 라이브러리/프레임워크 사용 자제 DOM 조작이 많거나 무거운 라이브러리는 Reflow/Repaint를 과도하게 유발할 수 있습니다. 프로젝트의 규모와 필요에 맞는 가벼운 대안을 고려하세요.
- CSS 애니메이션 대신 CSS Transitions 활용 간단한 애니메이션 효과는 JavaScript 없이 CSS Transitions만으로도 충분히 구현할 수 있으며, 브라우저가 이를 최적화하기 더 쉽습니다.
- 성능 예산 설정 특정 페이지나 컴포넌트의 Reflow/Repaint 시간을 측정하고, 허용 가능한 성능 목표(예: 16ms 이내)를 설정하세요. 모든 것을 완벽하게 최적화하기보다, 가장 큰 병목 현상부터 개선하는 데 집중합니다.
- 점진적 개선 한 번에 모든 것을 바꾸려 하지 말고, 개발자 도구로 발견된 가장 큰 성능 문제부터 점진적으로 해결해나 가세요. 작은 개선들이 모여 큰 효과를 만듭니다.
- 코드 리뷰 Reflow/Repaint를 유발할 수 있는 코드 패턴(예: 반복적인 레이아웃 정보 요청)에 대한 인지도를 높이고, 동료들과의 코드 리뷰를 통해 미리 방지하는 문화를 만드세요.
이 가이드가 웹 성능 최적화에 대한 이해를 돕고, 더 나은 사용자 경험을 제공하는 데 기여하기를 바랍니다.
'생활 정보' 카테고리의 다른 글
| Layout Thrashing을 유발하는 CSS 패턴과 피하는 방법 (0) | 2025.12.18 |
|---|---|
| CSS 속성별 GPU 가속 여부 정리 (transform, filter, opacity 등) (0) | 2025.12.18 |
| CSS에서 글자 크기가 줄어들지 않을 때 발생하는 흔한 원인 (0) | 2025.12.15 |
| margin이 안 먹는 이유와 해결 팁 (0) | 2025.12.14 |
| margin과 padding을 가장 쉽게 구분하는 비유 (0) | 2025.12.13 |