render_thumnail-min.png

렌더링이란?

단어 그대로 렌더링이란 HTML, CSS, JavaScript 등 개발자가 작성한 문서들을 브라우저가 화면에 그려주는 동작을 말한다. 각 브라우저는 렌더링을 하기 위해 각각의 렌더링 엔진을 가지고 있으며 브라우저마다 종류가 다를 수 있다.

브라우저의 기본 구조

브라우저의 렌더링 과정을 이해하기 전에 일단 브라우저가 어떻게 구성되어 있는지 주요 기본 구성 요소를 살펴보자!

browser_structure-min.png

각 구성 요소는 다음과 같은 역할을 하고 있다. 물론 구조는 브라우저마다 조금씩 다를 수 있다.

  • 사용자 인터페이스: 주소 표시줄, 이전/다음 버튼, 북마크 등 페이지 뷰 이외의 다른 부분
  • 브라우저 엔진: 사용자 인터페이스와 렌더링 엔진 사이 동작 제어
  • 렌더링 엔진: HTML, CSS를 파싱해 화면에 요청한 컨텐츠를 표시
  • 통신: HTTP요청과 같은 네트워크 호출에 사용됨
  • JS 엔진: 자바스크립트 코드를 해석하고 실행
  • UI 백엔드: 기본적인 위젯(콤보 박스 등)을 그림
  • 자료 저장소: 자료를 저장하는 계층으로 쿠키 등을 저장하는 웹 데이터베이스

이번 포스트에서는 렌더링 엔진을 통해 브라우저가 HTML, CSS, JavaScript 코드를 화면에 그려주는 과정을 포스팅하려고 한다.

렌더링 엔진

렌더링 엔진은 위에서 설명한 것처럼 요청받은 내용을 브라우저 화면에 표시해주는 역할을 한다. 브라우저마다 사용하는 렌더링 엔진이 각각 다르기 때문에, 모든 브라우저가 동일한 소스를 화면에 동일하게 그려주지 않고 엔진마다 읽을 수 있는 코드의 버전도 다르기 때문에 크로스 브라우징 이슈가 발생하곤 한다.

파이어폭스는 게코(Gecko), 사파리는 웹킷(Webkit), 크롬의 경우 웹킷을 사용하다가 웹킷을 Fork하여 블링크 엔진을 자체적으로 구현하여 사용한다. 각각의 렌더링 엔진들은 웹 표준에 따라서 개발자들이 작성한 문서를 브라우저에 보여주지만, 개발 진척도나 별도 규칙에 따라 지원하는 표준이 다르거나 렌더링 알고리즘과 방식에 차이가 있을 수 있다.

렌더링 엔진 동작 과정

다음은 렌더링 엔진의 기본적인 동작 과정이다.

render-min.png

DOM, CSSOM 트리를 구축 후 이 둘을 사용해 렌더 트리를 구축하고 배치 및 그리는 과정으로 동작한다. 그러면 이 과정에 대해 웹킷 엔진을 기준으로 좀 더 자세하게 알아보자!

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

tree-min.png

첫 번째로 브라우저가 렌더링할 문서를 읽게 되는데 HTML과 CSS로 나눠서 읽게 된다. 이때 HTML과 CSS는 단순한 텍스트이므로 각각 연산과 관리가 가능하도록 HTML Parser와 CSS Parser를 사용해 관리가 가능한 Object Model로 만든다.

여기서 렌더링 엔진은 더 나은 사용자 경험을 위해 가능한 빠르게 내용을 표시하게 만들어졌는데, 따라서 모든 HTML, CSS파싱이 끝나기도 전에 이후의 과정을 수행하여 미리 사용자에게 보여줄 수 있는 내용들을 출력한다.

렌더 트리 구축 (Attachment)

attach-min.png

전 단계에서 DOM 트리와 CSSOM 트리가 생성되면, 이 둘을 연결하여 표시해야 할 순서로 내용을 그려낼 수 있도록 하기 위해 렌더 트리를 생성해준다. 이 과정을 Attachment 라고 한다.

순수한 요소들의 구조와 텍스트만 존재하는 DOM 트리와는 달리 렌더 트리는 스타일 정보가 설정되어 있으며 실제 화면에 표현되는 노드들로만 구성된다. display: none;과 같은 속성이 설정된 노드는 화면에서 어떠한 공간도 차지하고 있지 않기 때문에 렌더 트리를 만드는 과정에서 제외된다.

렌더 트리 배치 (Layout or Reflow)

layout-min.png

렌더 트리가 생성되면 브라우저의 뷰포트 내에서 각 노드들의 정확한 위치와 크기를 계산한다. 이때 %, vh, vw와 같이 상대적인 위치, 크기 속성은 모두 실제 화면에 그려지는 px단위로 변환되며 이 과정을 Layout 또는 Reflow 라고 한다.

렌더 트리 그리기 (Paint)

painting-min.png

Layout과정이 완료되면 요소들의 위치와 크기, 스타일 계산이 완료된 렌더 트리를 사용해 브라우저는 요소들을 실제 화면에 그리게 된다. 이 과정을 Paint 라고 한다.

이 때, 처리해야 하는 스타일이 복잡할수록 Paint단계에 소요되는 시간이 길어지게 된다. 간단한 예시로 단순한 단색 background-color, color 등의 경우 Painting 속도가 빠르지만 그라데이션이나 그림자 효과 등 복잡한 스타일은 Painting 소요시간이 비교적 더 오래 소요된다.

렌더링 최적화

렌더링 과정을 모두 마친 후 최종적으로 브라우저에 페이지가 그려진다고 해서 렌더링 과정이 모두 끝난 것이 아니다. 특정 액션이나 이벤트에 따라 HTML요소의 크기나 위치 등의 레이아웃 수치를 수정하면 그에 영향을 받는 자식 노드나 부모 노드들을 포함하여 Layout(Reflow)과정을 다시 수행하게 된다.

이렇게 되면 렌더 트리와 각 요소들의 크기와 위치를 다시 계산하게 되는데 이 과정을 Reflow, 그리고 Reflow된 렌더 트리를 다시 화면에 그려주는 과정을 Repaint라고 한다.

Reflow

위에서 말한 것처럼 렌더 트리와 각 요소들의 크기와 위치를 다시 계산해주는 과정을 Reflow라고 한다.

Reflow가 일어나는 대표적인 경우는 다음과 같다.

  • 페이지 초기 렌더링 시 (최초 Layout 과정)
  • 브라우저 리사이징 시 (Viewport 크기 변경)
  • 노드 추가 또는 제거
  • 요소의 위치, 크기 변경
  • 폰트 변경과 이미지 크기 변경

Repaint

Reflow만 수행되면 실제 화면에는 반영되지 않기 때문에 다시 Painting이 일어나야 한다. 이 과정을 Repaint라고 한다.

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

렌더링 최적화 방법

그러면 브라우저에서 렌더링을 최적화 할 수 있는 방법에 대해 알아보자!

Reflow 최소화하기

브라우저가 더 렌더링을 빠르고 효율적으로 할 수 있게 개발하기 위해서는 Reflow과정을 최소화 시키는 것이 좋다. Reflow가 발생하면 필연적으로 Repaint가 일어나기 때문에 렌더링 최적화에 좋지 않은 영향을 준다. 그러므로 Reflow가 발생하는 속성보다 Repaint만 발생하는 속성을 사용하는 것이 좋다.

Reflow가 일어나는 대표적인 속성

position, width, height, left, top, right, bottom, margin, padding, border, border-width,
clear, display, float, font-family, font-size, font-weight, line-height, min-height,
overflow, text-align, vertical-align, white-space...

Repaint가 일어나는 대표적인 속성

background, background-image, background-position, background-repeat, background-size,
border-radius, border-style, box-shadow, color, line-style, outline, outline-color,
outline-style, outline-width, text-decoration, visibilty...
영향을 주는 노드 최소화하기

JavaScript와 CSS를 조합해 애니메이션이나 레이아웃 변화가 많은 요소의 경우 positionabsolute 또는 fixed를 사용하면 영향을 받는 주변 노드들을 줄일 수 있다.

fixed와 같이 영향을 받는 노드가 전혀 없는 경우 Reflow과정이 전혀 필요없어지기 때문에 Repaint연산비용만 들게 되어 효율적이다.

프레임 줄이기

단순하게 생각하면 0.1초마다 1px씩 이동하는 요소보다 0.3초마다 3px씩 이동하는 요소가 Reflow 연산비용이 3배가 줄어든다고 볼 수 있다. 따라서 부드러운 효과를 조금 줄이면서 성능 개선을 할 수 있다.

결론

이번 포스트에서는 브라우저 렌더링 과정과 렌더링 최적화 과정에 대해 알아보았는데 프론트엔드 개발자라면 알고있어야 할 개념같았다. 특히 평소에 css 속성 중 Reflow가 자주 일어나는 속성을 생각없이 사용하곤 했는데 이런 부분까지 신경 쓴다면 좀 더 경쟁력 있는 개발자로 성장할 수 있을 것 같다.

본 포스트는 다음 문서를 참고해 작성했습니다.

https://d2.naver.com/helloworld/59361

https://beomy.github.io/tech/browser/browser-rendering/