Reflow와 Repaint

ggong·2021년 5월 14일
1

웹 개발을 하면서 브라우저의 렌더링 과정을 정확히 알고 있어야 성능에 대해서도 제대로 고민할 수 있다는 생각이 들었다. 오늘은 성능 최적화를 위해 꼭 알고 있어야 하는 Reflow, Repaint 개념을 정리해 보려고 한다.

1. 브라우저와 렌더링 엔진

브라우저의 주요 기능은 사용자가 요청한 자원을 서버에서 받아 화면에 그려주는 것이다. 브라우저는 HTML과 CSS 소스를 파싱해 컨텐츠를 표시하는데, 이 과정을 수행하는 각자의 렌더링 엔진을 가지고 있다. 예전에는 각 렌더링 엔진마다 명세가 다르고 독자적으로 기능을 지원했기 때문에 개발자가 호환성 문제를 겪었지만, 최근에는 대부분 명시된 기술 명세를 따르고 있다.
브라우저마다 사용하는 엔진은 아래와 같다.

사파리 - 웹킷(webkit)
파이어폭스 - 게코(Gecko)
크롬 - 웹킷에서 fork된 블링크(Blink) 사용
IE - 트라이던트(Trident)


2. 브라우저의 렌더링 과정

렌더링 엔진의 처리 과정은 아래의 순서대로 이루어진다.

렌더링 엔진은 HTML, CSS 파일을 받아와 파싱하면서 DOM(Document Object Model), CSSOM(CSS Object Model)을 생성한다. 이렇게 DOM tree, CSSOM tree가 생성되면 이 둘을 합쳐 '렌더 트리'가 구성된다. 렌더 트리는 실제 화면에 표시되는 노드들로 구성되며, CSS 속성에 따라 display: none과 같은 속성을 가진 노드는 렌더 트리에 포함되지 않는다. 비슷한 속성이더라도 visibility: invisible은 공간은 차지하고 요소만 보이지 않도록 처리하는 것이므로 노드 트리에 표시된다.

렌더 트리 구성이 끝나면 다음은 Layout 단계가 실행되어 브라우저는 viewport 내에서 각 노드의 크기와 위치를 계산한다. 즉, 렌더 트리 안에 있는 노드들이 가진 스타일 속성에 따라 화면에 출력될 정확한 레이아웃을 계산하는 것이다. 여기서 viewport란 화면이 표시되는 브라우저의 넓이를 말한다.
노드의 스타일 속성 중 vw, vh, %와 같은 상대적 단위가 있다면 이것들도 실제 pixel 숫자로 계산하여 처리된다. 이 계산은 HTML 문서의 <html> 태그에 해당하는 최상위 렌더러에서 시작된다.

Layout 단계가 끝나면 이제 브라우저는 계산된 값으로 실제 화면을 그린다. 이것을 Paint 단계라고 한다. 위치와 크기, 스타일 속성을 통해 정확한 레이아웃 정보를 가진 노드들이 화면에 배치되고 컬러, 그라데이션, 이미지와 같은 부가적인 스타일 속성들도 적용된다.

3. Reflow와 Repaint

Reflow란 위처럼 브라우저가 렌더링을 하는 과정에서 Layout 단계가 다시 수행되는 것을 말한다. 브라우저 렌더링 최초 실행 후에 어떤 이벤트나 액션에 의해 레이아웃에 변경이 생기면, 변경이 일어난 노드의 크기나 위치 등이 다시 계산되어야 한다. 또한 변경된 요소에 영향을 받는 자식 노드들의 위치도 다시 계산이 필요하다. 이렇게 추가적인 레이아웃 조정으로 인해 노드들이 재배치 되는 과정을 Reflow라고 한다. Reflow가 일어난 후에는 재 계산된 결과를 다시 그려주는 Repaint 단계가 실행된다.

이 과정에서 브라우저는 변경에 대해 최소한의 동작으로 반응하려고 한다. 만약 어떤 요소의 color나 visibility가 바뀌면 해당 요소에 대해서는 레이아웃을 재계산할 필요가 없으므로 화면에만 다시 그려지는 Repaint만 일어난다. 만약 요소의 위치가 바뀌면 해당 요소와 그 형제노드, 하위에 있는 자식노드에도 영향을 미쳐 재배치가 추가로 필요하므로 Reflow와 Repaint가 모두 일어난다.

Reflow가 일어나는 대표적인 케이스는 다음과 같다.

  1. 윈도우 리사이징 시 (viewport가 변경되었을 경우)
  2. 노드의 추가 혹은 제거
  3. 요소의 위치, 크기가 변경되었을 경우
  4. 폰트 변경, 텍스트의 추가 혹은 제거, 이미지 크기 변경이 일어난 경우

CSS 스타일 속성 중에서도 Reflow를 일으키는 속성들이 있다. 이러한 속성들이 많다면 그만큼 연산과 재배치가 많이 일어나는 것이므로, 성능 최적화를 위해서는 Reflow를 피할 수 있는 속성으로 대체해서 사용하는 것이 좋다.

4. 성능 최적화를 위해 할 수 있는 것들

  1. 레이아웃의 변화가 많은 경우 positionfixedabsolute를 사용한다. 절대와 고정 포지션으로 배치된 엘리먼트는 다른 엘리먼트의 위치에 영향을 미치지 않는다. 고정인 경우에는 뷰포트로부터 위치를 결정한다.
  2. 애니메이션을 구현할 때는 프레임을 조절한다. 엘리먼트를 0.1초당 1px씩 4번 이동시키면 부드러운 UX를 구현할 수 있지만, 그만큼 많은 Reflow와 Repaint가 발생한다. 대신 엘리먼트를 4px 이동하면 덜 부드럽게 보이겠지만, Reflow를 1/4로 줄일 수 있다.
  3. 화면에서 숨겨지는 노드에는 visibility: invisible보다 display:none 속성을 사용한다. visibility는 화면에 보이지 않더라도 레이아웃 상에서 공간을 차지하기 때문에 Reflow의 영향을 받는다.
  4. CSS 하위 셀렉터를 최소화하고, 클래스 변경을 통해 스타일을 제어할 때는 최대한 마지막 단계에 있는 노드의 클래스를 변경시켜 영향 받는 범위를 줄인다.
  5. 자바스크립트를 통해 스타일을 변경할 경우, cssText를 사용하여 한번에 설정하는 것이 좋다.
var el = document.getElementById('reflow-test');

el.style.padding = '8px';
el.style.width = '320px';
el.style.height = '240px';
// 3번의 리플로우 발생

el.style.cssText = 'padding: 8px; width: 320px; height: 240px;';
// 1번의 리플로우 발생



참고:
브라우저는 어떻게 동작하는가? (https://d2.naver.com/helloworld/59361)
브라우저 렌더링 과정 - Reflow Repaint, 그리고 성능 최적화
(https://boxfoxs.tistory.com/408)
Reflow 와 Repaint
(https://github.com/wonism/TIL/blob/master/front-end/browser/reflow-repaint.md)

profile
파닥파닥 FE 개발자의 기록용 블로그

0개의 댓글