기록하는 개발자

브라우저의 렌더링 과정과 Reflow, Repaint 본문

Web

브라우저의 렌더링 과정과 Reflow, Repaint

밍맹030 2023. 12. 19. 18:39
728x90

브라우저의 렌더링 과정

Parsing→Style→Layout→Paint→Composite

 

 

Parsing(DOM Tree, CSSOM Tree 구성)

HTML 파일과 CSS 파일을 파싱해서 각각 Tree를 만든다.

브라우저가 페이지를 렌더링하려면 가장 먼저 받아온 HTML 파일을 해석해야한다. Parsing 단계는 HTML 파일을 해석하여 DOM(Document Object Model) Tree를 구성하는 단계이다. CSS가 포함되어 있다면 CSSOM(CSS Object Model) Tree 구성 작업도 함께 진행한다.

 

 

Style(Render Tree 구성)

Parsing 단계에서 생성된 DOM Tree와 CSSOM Tree를 매칭시켜서 Render Tree를 구성한다. Render Tree는 실제로 화면에 그려질 Tree이다.

 

 

Layout(Render Tree 배치 : Reflow)

Render Tree를 화면에 어떻게 배치해야 할 것인지 Node의 정확한 위치와 크기를 계산한다.

Root부터 노드를 순회 하면서 노드의 정확한 크기와 위치를 계산하고 Render Tree에 반영한다.

만약 크기 값을 %로 지정 하였다면, Layout 단계에서 % 값을 계산해서 픽셀 단위로 변환한다.

 

Paint(Render Tree 그리기 : Repaint)

Layout 단계에서 계산된 값을 이용해 Render Tree의 각 노드를 화면상의 실제 픽셀로 변환하고 레이어를 만든다.

이때 픽셀로 변환된 결과는 하나의 레이어가 아니라 여러 개의 레이어로 관리된다. 스타일이 복잡할수록 Paint 시간도 늘어난다.

Ex)단색 배경은 시간과 작업이 적게 필요하지만 그림자 효과는 더 많이 소요됨

 

Composite

Paint 단계에서 생성된 레이어를 합성하여 실제 화면에 나타낸다. 우리는 화면에서 웹 페이지를 볼 수 있다.

 

 

Reflow와 Repaint

 

Reflow

Parsing → Style(RenderTree 생성)→ Reflow(Layout) → Repaint → Composite

 

생성된 DOM 노드의 레이아웃 수치(너비, 높이, 위치 등)가 변경되면 영향 받은 모든 노드의(자신, 자식, 부모, 조상(결국 모든 노드)) 수치를 다시 계산하여 렌더 트리를 재생성하는 과정

 

• DOM 엘리먼트나 css 스타일이 추가, 제거 또는 변경되었을 때

• User Interaction으로 발생하는 hover 효과, 필드에 텍스트 입력, 창 크기 조정, 글꼴 크기 변경 등이 발생할 때

 

Repaint

Parsing → Style(RenderTree 생성)→ Repaint → Composite

 

RenderTree가 탐색되고 paint 메서드가 호출되어 화면을 그리는 과정이다.

따라서, Repaint가 이루어지기 위해서는 RenderTree가 있어야 하고, Reflow 작업이 이루어진 후에 재생성된 렌더 트리를 다시 그리게 되는 과정인 Repaint 작업이 이루어진다.

 

즉, 화면의 구조가 변경이 될 때는 Reflow와 Repaint가 모두 발생한다.

 

Reflow가 발생하지 않고 Repaint만 발생하는 경우도 있는데, 화면의 가시성은 변하지만 레이아웃에 영향을 미치지 않는 요소의 외관을 변경할 때이다.

 

 Reflow가 실행된 후

• 가시성이 변경되는 순간 (opacity, background-color, visibility, outline)

 

Reflow를 최소화하는 방법

w3c에 소개된 Reflow를 최소화하는 방법 중 몇 가지를 가져와봤다.

 

1. 클래스 변화에 따른 스타일 변화를 원할 경우, 최대한 DOM 구조 상 끝단에 위치한 노드에 주어라.

<div className="Wrapper">
  <div className="list-Wrapper">
    <ul className="list-ul">
      <li></li>
      <li></li>
      <li></li>
    </ul>
  </div>
</div>

클래스 변화로 인한 Reflow를 아예 피할 수는 없겠지만, 그 효과는 줄일 수 있다. DOM 트리에서 가급적 말단에 위치한 노드에 클래스 변화를 줄 경우, 이는 Reflow의 행동 반경을 전체 페이지가 아닌 일부 노드들로 제한할 수 있다. 따라서 전체 페이지를 감싸는 wrapper에 클래스를 수정하는 행위는 꼭 피해야 한다. 또한 OOCSS(Object Oriented CSS) 방식을 통해 클래스변화가 발생할 경우, 특정 엘리먼트에 대해 상당히 많은 클래스를 적용시키는 것 같지만, 실제로는 Reflow의 영향을 최소화함으로써 퍼포먼스적인 측면에서 큰 이득이 발생한다.

 

 

2. Inline Style을 최대한 배제하라.

DOM은 매우 느린 구조체이다. 게다가 inline으로 스타일이 주어진 경우, Reflow는 페이지 전체에 걸쳐 수차례 발생하게 된다. 만일 inline style이 없을 경우, 외부 style 클래스의 조합으로 단 한번만 Reflow를 발생시킨다.

 

 

3. 애니메이션이 들어간 엘리먼트는 가급적 position:fixed 또는 absolute 로 지정

일반적으로 JS(특히 jQuery)나 CSS3로 width/height 또는 위치이동을 구현한 애니메이션은 거의 초단위로 상당한 Reflow를 불러일으킨다. 이러한 경우에 해당 개체의 position 속성을 fixed 또는 absoute로 주게 되면 다른 요소들의 레이아웃에 영향을 끼치지 않으므로 페이지 전체의 Reflow 대신 해당 애니메이션요소의 Repaint만을 유발하므로 비용적인 측면에서 매우 효율적인 방법이다.

 

 

4. 테이블 레이아웃을 피하라

테이블로 구성된 페이지 레이아웃은 점진적(progressive) 페이지 렌더링이 적용되지 않으며, 모두 로드되고 계산된 후에야 화면에 뿌려진다. Mozilla에 따르면 테이블 레이아웃에서는 아주 작은 변화마저도 해당 테이블 전체 모든 노드에 대한 Reflow를 발생시킨다고 한다.

 

 

5. JS를 통해 스타일변화를 주어야 할 경우, 가급적 한번에 처리하라

특정 요소에 스타일변화를 주어야 할 경우 다음과 같이 시도해볼 수 있다.

var toChange = document.getElementById('elem');

toChange.style.background = '#333';
toChange.style.color = '#fff';
toChange.style.border = '1px solid #ccc';

 

이러한 접근은 여러번 중복된 Reflow와 Repaint를 유발시킨다. 때문에 아래와 같이 단 한번의 변화만 발생시키는 것이 더욱 효과적이다.

/* CSS */ 
#elem { 
	border:1px solid #000; color:#000; background:#ddd;
} 
.highlight { 
	border-color:#00f; color:#fff; background:#333; 
} 
 
/* js */
document.getElementById('elem').className = 'highlight';

참고

https://lists.w3.org/Archives/Public/public-html-ig-ko/2011Sep/att-0031/Reflow_____________________________Tip.pdf

https://velog.io/@young_pallete/Reflow-Repaint%EC%9D%84-%EC%95%8C%EC%95%84%EB%B3%B4%EC%9E%90

https://devowen.com/463

https://ekimnida.tistory.com/45

728x90