브라우저 렌더링 과정

1. 렌더링 엔진

  1. 대부분의 브라우저는 렌더링을 수행하는 렌더링 엔진을 가지고 있다.
  2. 다만 모든 브라우저가 같은 렌더링 엔진을 사용하지는 않는다. 사파리의 경우 대부분이 알고있는 webkit 엔진을 사용한다.
  3. 각 브라우저별로 테스트를 수행하여 여러 브라우저의 호환성에 문제가 없는지 검사해야한다.

1.5. DOM 과 BOM

렌더링 과정을 알기전에 DOM과 BOM을 알고 지나가자.

우선 BOM(Brower Object Model)은 브라우저의 창이나 프레임을 프로그래밍적으로 제어할 수 있게 해주는 객체모델 이다. 이를 통해서 브라우저의 새 창을 열거나 다른 문서로 이동하는 등의 기능을 실행시킬 수 있다. 전역 객체로 window가 있으며 하위 객체들로 location, navigator, history, screen, document가 포함되어 있다.

DOM(Document Object Model)은 웹페이지를 프로그래밍적으로 제어할 수 있게 해주는 객체모델이다(HTML, XML 문서의 프로그래밍 interface ). 최상위 인터페이스로 Node가 있다.

내가 작성한 HTML 코드가 DOM일까 ? 아니다 브라우저에 파싱되면 DOM이 된다.

image

예시로

<!DOCTYPE html>
<html>
  <head>
    <title>제목</title>
  </head>
  <body>
  <div class="클래스"></div>
  <!-- 주석 -->
  <a href="https://naver.com">네이버</a>
  </body>
</html>

위와 같은 코드가 있을 때

dom2.png

Live DOM viewer를 사용하면 위와같은 DOM트리가 완성된다. 보면 텍스트 노드와 주석 노드까지 포함된걸 볼 수 있다.( 주석 제거 잘 해야겠네..) 이런 DOM을 다루기 위해선 document.querySelector와 같은 DOM API를 사용하면 된다.

2. 렌더링 과정

DOM (Document Object Model), CSSOM (CSS Object Model) 생성

첫번째 단계는 서버로부터 받은 HTML, CSS를 다운로드 받는다. 받은 HTML, CSS 파일은 단순한 텍스트이므로 연산과 관리가 유리한 Object Model을 만든다. 이 과정에서 HTML, CSS 파일은 각각 DOM TreeCSSOM으로 만들어진다.

추가적으로 렌더링 엔진은 더 나은 UX(사용자 경험) 을 위해 모든 HTML 파싱이 끝나기 전에 사용자에게 보여줄 수 있는 일부 내용들을 미리 출력한다.

Render Tree 생성

DOM Tree와 CSS Tree를 이용하여 Render Tree를 생성한다. DOM Tree는 순수한 요소들의 구조와 텍스트만 존재한다. 하지만 Render Tree를 만드는 과정에서 각 요소들의 스타일이 계산되고, 이 과정에서 다른 요소들의 스타일 속성들을 참조한다. 따라서 Render Tree는 스타일 정보가 설정되어 있고 실제 화면에 표현되는 노드들로만 구성된다.

여기서 실제 화면에 표현되지 않는 노드의 예시는 display: none 속성이 설정된 노드이다. 반면에 visibility: invisible은 화면에 표시되지 않지만 공간을 차지하기 때문에 Render Tree에 포함된다.

추가적으로, Webkit ( 크롬 브라우저 엔진 ) 에서는 노드의 스타일을 처리하는 과정을 attachment 라고 한다. DOM Tree의 모든 노드들은 attach라는 메소드가 있고, 이 메소드는 노드의 스타일 정보를 계산하여 객체형태로 반환한다. 이 과정은 동기적으로 일어난다.

동기적으로 처리되니 JS로 DOM 요소의 속성을 변경할 때 한번에 처리해주면 Reflow 발생 횟수가 줄어들겠네..

Layout

Render Tree 노드들이 가지고 있는 스타일 정보와 속성을 이용해서 브라우저에 어느위치에 어느크기로 출력될지 계산하는 단계이다. 이 과정에서 %, vh, vw 와 같은 상대적인 위치, 크기 속성들은 실제 화면에 그려지는 pixel 단위로 변환된다.

뷰포트(Viewport)란? 그래픽이 표시되는 브라우저의 영역, 크기를 말한다.

Paint

Layout 단계에서 계산이 완료되면 요소들을 실제 화면에 그리게 된다. 이때 텍스트, 색, 이미지, 그림자 효과등이 모두 처리되어 그려진다. ( paint() 메소드 호출 )

Composite

페이지의 여러 부분이 잠재적으로 여러 레이어로 그려졌기 때문에 페이지가 정확히 렌더링되려면 정확한 순서로 화면에 그려야 합니다. 실수로 한 요소가 다른 요소 위에 잘못 나타날 수 있기 때문에 이는 다른 요소와 겹치는 요소가 있는 경우에 특히 중요합니다.


3. Reflow와 Refaint

Reflow (Render Tree 생성 ~ Layout)

위에서 말한 과정을 거친 뒤에 페이지가 그려진다고 해서 렌더링 과정이 다 끝난것이 아니다. 어떠한 액션이나 이벤트에 따라 HTML의 요소의 크기나 위치등 레이아웃 수치를 수정하면 그에 영향을 받는 자식 노드나 부모 노드를 포함하여 Layout 과정을 다시 수행하게 된다. 이렇게 되면 Render Tree와 각 요소들의 크기와 위치를 다시 계산하게 된다. 이러한 과정을 Reflow 라고 한다.

대표적인 예시는

  • 페이지 초기 렌더링 시 ( 최소 Layout 과정 )
  • 윈도우 리사이징 시 ( Viewport 크기 변경시)
  • 노드 추가 또는 제거
  • 요소의 위치, 크기 변경 (left, top, margin, padding, border, width, height 등)
  • 폰트 변경 과(텍스트 내용) 이미지 크기 변경(크기가 다른 이미지로 교체)

Repaint (paint)

Reflow만 수행되면 실제 화면에 반영되지 않는다. 위에서 언급된 렌더링 과정과 같이 Render Tree를 다시 화면에 그려주는 과정이 필요하다. 결국 Paint 단계가 다시 수행되는 것이며 이를 Repaint 라고 한다.

무조건 Reflow가 일어나야 Refaint가 일어나는게 아니다. 예를들어 background-color 변경 같은 레이아웃에 영향을 주지 않는 스타일 속성이 변경되었을 때는 Reflow를 수행할 필요가 없기 때문에 Repaint만 수행하게 된다.


3.5 렌더링 최척화

렌더링을 최척화하는 몇가지 예시

  1. css visibility: invisible 속성보다 display: none 속성을 사용한다. display 속성은 렌더트리에 포함되지 않기 때문에 연산을 해야할 노드의 개수가 줄어든다!
  2. position: absolute, fixed를 사용해서 주변노드에 영향을 줄인다.
  3. transform 속성을 사용할 수 있으면 사용하자. 이는 reflow, repaint가 일어나지 않고 composite 단계만 거치기 때문이다.

4. Why Virtual DOM?

일반적으로 dom에 접근하여 여러번의 속성 변화, 여러번의 스타일 변화를 수행하면 그에따라 Render Tree를 만들고 ( Reflow ) 다시 그리는 ( Refaint ) 작업을 여러번하게 된다. 하지만 Virtual DOM은 이렇게 변화가 일어나는 사항들을 한번에 묶어서 실제 DOM에 전달하게 된다. 따라서 실제 연산은 딱 한번만 수행하게 된다. 이를 통해 여러번 Reflow, Refaint를 수행하며 연산이 반복적으로 일어나는 부분이 줄어들어 성능이 개선된다.


5. Reference

  1. https://velog.io/@godori/DOM%EC%9D%B4%EB%9E%80-%EB%AC%B4%EC%97%87%EC%9D%B8%EA%B0%80
  2. https://boxfoxs.tistory.com/408
  3. https://velopert.com/3236
  4. https://falsy.me/%EB%B8%8C%EB%9D%BC%EC%9A%B0%EC%A0%80%EC%9D%98-%EC%9D%B4%ED%95%B4-1-reflow-repaint%EC%97%90-%EB%8C%80%ED%95%98%EC%97%AC-%EC%95%8C%EC%95%84%EB%B4%85%EB%8B%88%EB%8B%A4/
  5. https://github.com/baeharam/Must-Know-About-Frontend/blob/master/Notes/frontend/bom-dom.md


Written by@[HongDongUk]
공부한 것을 소소하게 적는 블로그.

GitHubFacebook