📝

15. 브라우저 렌더링 과정

 

15-1. 브라우저란?

웹 브라우저(web browser)는 기본적으로 웹 서버에서 받아온 정보를 화면에 출력한다. 서버에서 받아온 정보는 HTML 문서, 이미지, 비디오 등이 있다. 주요 웹 브라우저는 Chrome, Firefox, Internet Explorer, Safari 및 Opera가 있다. 웹 트래픽(Web Traffic, 웹 사이트에 방문한 사람들이 주고받은 데이터의 양으로 방문자 수와 방문 페이지 수에 따라 결정됨)의 95%를 차지한다.
웹 서버는 해당 정보를 HTTP(HyperText Transfer Protocol)를 따라 클라이언트 웹 브라우저에 전송하며, 웹 브라우저는 해당 결과를 표시한다.

15-1-1. 브라우저의 기본 구조

브라우저의 기본 구조는 그림과 같이 7가지 구성요소로 이루어져 있다.
알잘딱깔센 JavaScript알잘딱깔센 JavaScript
알잘딱깔센 JavaScript
1) User Interface (사용자 인터페이스)
  • 사용자가 웹 페이지에서 사용할 수 있는 모든 시각적 요소와 상호 작용할 수 있다. 시각적 요소에는 주소 표시줄, 뒤로 가기 버튼, 앞으로 가기 버튼, 새로고침, 홈 버튼 및 책갈피 표시줄과 같은 탐색 버튼이 있다.
  • 이런 버튼들과 웹 사이트에서 응답받은 콘텐츠를 표시하는 뷰포트(화면)가 있고 인터페이스의 특정 표준은 없으나 브라우저는 수년에 걸쳐 발전하며 UI가 개선되었다.
 
2) Browser Engine (브라우저 엔진)
  • 사용자 인터페이스와 렌더링 엔진 사이의 동작을 제어하며 모든 웹 브라우저의 핵심 구성 요소이다. 사용자가 주소 표시줄에 입력한 URL를 입력하면 URL를 전달받은 브라우저 엔진이 자료 저장소에서 해당 URL에 맞는 자료를 찾는다. 그리고 해당하는 자료들을 렌더링 엔진에 전달한다. 만약 자료 저장소에 저장된 자료가 없다면 URL 값만 렌더링 엔진에 전달한다.
 
3) Rendering Engine (렌더링 엔진)
알잘딱깔센 JavaScript알잘딱깔센 JavaScript
알잘딱깔센 JavaScript
  • 이름에서 알 수 있듯이 이 구성 요소는 사용자가 요청한 특정 웹 페이지를 화면에 렌더링 하는 역할을 한다. 브라우저 엔진에게 전달받은 HTML 및 XML 문서를 파싱 해서 요청한 웹페이지를 표시한다. URL 값만 전달받았다면, URL를 Networking에 전달해 데이터를 받아오고 JS Engine을 통해 받아온 JS 파일을 파싱 한 후, 생성된 Render Tree를 UI Backend로 전달한다.
 
💡 모든 브라우저에는 고유한 렌더링 엔진이 있다. 렌더링 엔진은 브라우저 버전에 따라 다르다. 아래 목록은 일반적인 브라우저에서 사용되는 브라우저 엔진 목록이다. - Google Chrome and Opera v.15+: Blink - Internet Explorer: Trident - Mozilla Firefox: Gecko - Chrome for iOS and Safari: WebKit
 
4) Networking (통신)
  • 렌더링 엔진으로부터 요청을 받아서 HTTP(HyperText Transfer Protocol) 또는 FTP(file transfer protocol)와 같은 표준 프로토콜을 사용하여 네트워크 호출을 관리하는 역할을 한다. 입력받은 URL에 해당하는 데이터를 렌더링 엔진에게 전달한다. 또한 인터넷 통신과 관련된 보안 문제를 처리한다.
 
5) JS Engine (자바스크립트 해석기)
  • Javascript Interpreter라고도 부르며 이름에서 알 수 있듯이 웹 사이트에 포함된 JavaScript 코드의 구문을 분석하고 실행하는 역할을 한다. 해석된 결과가 생성되면 사용자 인터페이스에 표시하기 위해 렌더링 엔진으로 전달된다.
 
6) Data Storage (자료 저장소)
  • 자료를 저장하는 계층으로 LocalStorage나 Cookie와 같이 보조기억장치에 데이터를 저장하는 자료 저장소이다. 자주 받아오는 자료를 저장해두어 서버에 반복적으로 요청하는 작업을 줄인다. 또한 자주 접근될 데이터를 더 빠른 속도의 메모리상에 가져와 연산을 수행해 성능을 최적화하는 캐싱 (Caching)이 이루어진다.
 
7) UI Backend (UI 백엔드)
  • 콤보 박스(Select box), 체크 박스, 버튼, 창 같은 기본적인 장치를 그려주는 구성 요소이다.
 

15-2. 브라우저 렌더링

15-2-1. 렌더링이란?

브라우저 렌더링은 사용자가 주소창에 특정 URL을 입력하여 접속하거나 링크를 클릭했을 때, 특정 양식 값을 제출했을 때 등 사용자의 요청이 있을 때 발생한다. 물론 사용자가 URL을 입력할 때마다 항상 서버에서 동일한 데이터를 받아오진 않는다. 이 때 필요한 최적화는 하단에서 살펴보도록 하자. 이렇게 브라우저 요청에 따라 URL과 연결되어 있는 서버에서 네트워크를 통해 데이터를 전송받는다. 렌더링 엔진은 전송받은 HTML 문서를 해석하여 사용자가 볼 수 있도록 화면에 그려준다. 이러한 과정을 렌더링이라고 한다.

15-2-2. 브라우저 렌더링 과정

브라우저의 종류마다 렌더링 엔진의 세부 과정 등은 약간의 차이가 있지만 전체적 작동 방식은 유사하므로 브라우저 렌더링 과정이 기본적으로 어떻게 진행되는지 살펴보자.
 
알잘깔딱센 JavaScript알잘깔딱센 JavaScript
알잘깔딱센 JavaScript
 
1. HTML 파싱 및 DOM 트리 구축
알잘딱깔센 JavaScript알잘딱깔센 JavaScript
알잘딱깔센 JavaScript
먼저 HTML문서를 파싱하고 DOM 트리를 구축한다. HTML 파싱에는 토큰화 및 트리구조를 포함한다. HTML 파싱 단계에서 렌더링 엔진은 서버에서 전송받은 바이트를 문자로 변환하고 토큰을 식별한다. 토큰화에는 시작태그와 종료태그를 포함하고 있으며, 속성과 값 또한 포함한다. 토큰 식별 후 노드로 전환하고 각 태그간의 관계와 계층 구조를 반영하여 DOM 트리를 구축한다. 파싱 중에 이미지같은 비동기 리소스를 만나면 브라우저가 해당 리소스를 요청하고 파싱을 계속 진행한다. 이 때 렌더링 엔진은 멈추지 않는다.
 
<header> <script src="script.js" async></script> </header>
 
만약 Script 요소를 만나면 렌더링은 중단되고 Script 엔진을 이용해 JavaScript를 먼저 해석한 이후 렌더링을 재개하게 된다. 이러한 중단을 막기위해 defer 또는 async 속성을 사용하여 렌더링이후에 JavaScript가 호출 될 수 있도록 한다.
 
2. CSS 파싱과 CSSOM 트리 구축
알잘딱깔센 JavaScript알잘딱깔센 JavaScript
알잘딱깔센 JavaScript
그 다음으로 CSS 문서를 파싱하고 CSSOM 트리를 구축한다. CSSOM은 CSS 객체 모델로 DOM과 유사하지만 둘은 서로 독립적인 데이터 구조이다. 브라우저는 DOM 트리를 구축하는 동안 head 섹션에서 외부 CSS 문서를 참조하는 링크태그를 만나고 해당 리소스를 CSS 규칙을 이해할 수 있는 스타일 지도로 전환한다. 이후 CSS 규칙을 바탕으로 CSS 선택자의 부모, 형제 관계를 트리로 구축한다. 이는 CSS 문서 또한 브라우저가 처리할 수 있는 형식으로 바꾸기 위해 변환되어야 하며 CSS에 대해 HTML 프로세스를 반복하는 것으로 서버에서 전송된 바이트가 문자, 토큰, 노드의 순서로 변환되어 CSSOM 트리로 빌드된다.
 
3. 렌더링 트리 구축
알잘딱깔센 JavaScript알잘딱깔센 JavaScript
알잘딱깔센 JavaScript
DOM 트리와 CSSOM 트리가 완료되면 브라우저 엔진은 각 트리를 결합한 렌더링 트리를 구축한다. 렌더링 트리는 웹 페이지에 그려낼 수 있는 모든 컨텐츠의 사이즈 및 위치를 계산하고 결정한다. 렌더링 트리 구축 이후 결정된 레이아웃은 화면에 픽셀로 나타난다. 렌더링 트리 형성과정에서 브라우저는 아래와 같은 작업을 수행한다.
  • script, meta 태그 등은 렌더링 출력에 반영되지 않아 해당 노드는 렌더링 트리에 반영되지 않는다.
  • display: none 과 같이 CSS를 통해 숨겨지는 노드는 렌더링에 출력되지 않으므로 렌더링 트리에서도 반영되지 않는다.
💡
visibility: hiddendisplay: none의차이점
  • visibility: hidden은 요소를 보이지 않게 하는 속성이기 때문에 레이아웃에서 공간을 차지하므로 렌더링 트리에 포함된다.
  • display: none 은 요소가 보이지 않을 뿐만 아니라 레이아웃에서도 영역을 차지하지 않기 때문에 렌더링 트리에 포함되지 않는다.
 
4. 레이아웃(렌더링 트리 배치)
렌더링 트리는 노드의 콘텐츠 및 스타일 정보를 모두 포함하고 있다. 이 렌더링 트리를 활용하여 뷰포트 내에서 요소들이 어디에 위치할지, 정확한 위치와 크기, 그 외의 스타일 속성를 계산하게 되는데 이 과정을 레이아웃 단계라고 한다.
레이아웃 단계에서는 %em같은 상대적인 값들을 모두 뷰포트에서 절대적인 픽셀단위로 변환한다.
 
<div style="width: 50%"> <div style="width: 50%"></div> </div>
 
예를 들어 뷰포트가 1000px일 때, width가 50%인 div를 하나 만들고 그 안에 width가 50%인 하위 div를 만들었을 경우에, 레이아웃 과정에서는 상위 divwidth를 뷰포트의 50%인 500px로, 하위 divwidth를 뷰포트의 25%인 250px로 계산한다.
뷰포트가 500px일 경우에는, 상위 divwidth는 250px, 하위 divwidth는 125px로 계산한다.
 
5. 페인트(렌더링 트리 그리기)
이렇게 레이아웃 단계에서 요소들의 기하학적인 구조를 알게 되면 화면에 실제로 나타내게 되는데 이 단계를 페인트 단계라고 한다. 렌더링 트리를 따라서 페인트 기록을 만들어 실제 화면의 픽셀로 그리는 작업이다. 스타일이 복잡할 수록 페인트 단계에서 소요되는 시간은 길어지게 된다.
 
6. 컴포지팅
브라우저가 필요에 의해 페인팅할 레이어를 나누어 놓는 작업이다. 각각의 레이어를 합성해 하나의 페이지를 구성하게 된다.

15-3. reflow, repaint, 컴포지팅

페이지가 화면에 표시되었다고 해서 끝이 아니다. 마우스 클릭, 애니메이션 등 다양한 이벤트에 따라서 다시 화면에 그려주는 작업을 수행하게 된다. 하지만 일부 UI의 변경으로 모든 렌더링 과정을 다시 진행하지는 않는다. 상황에 따라 크게 세 가지로 나눌 수 있다.

15-3-1. reflow

높이, 넓이, 위치 등 수치적으로 변화가 있어 레이아웃 단계부터 다시 시작해 새로 렌더링 트리를 만들어줘야 하는 작업이다.
알잘딱깔센 JavaScript알잘딱깔센 JavaScript
알잘딱깔센 JavaScript
reflow가 일어나면 새로운 렌더링 트리가 만들어졌기 때문에 그것에 맞추어 다시 페인트(repaint), 컴포지팅 작업이 이어져야 한다.
 

15-3-2. repaint

reflow 이후에 새로 만들어진 렌더링 트리를 다시 화면에 페인트해주는 작업을 repaint라고 한다.
reflow가 일어나지않더라도 repaint는 일어날 수 있다. 색상 변경처럼 크기 변경과 같은 수치적인 변경이 이루어지지 않은 경우에는 렌더링 트리를 다시 만들 필요가 없기 때문에 repaint만 일어나게 된다.
알잘딱깔센 JavaScript알잘딱깔센 JavaScript
알잘딱깔센 JavaScript
 

15-3-3. 컴포지팅

하나의 레이어 내에서만 변경이 일어나는 경우이다. 가장 비용이 적게 드는 경우로 레이아웃 단계와 페인트 단계는 건너뛰고 컴포지팅 단계에서의 변화만 일어난다.
알잘딱깔센 JavaScript알잘딱깔센 JavaScript
알잘딱깔센 JavaScript
transform이 대표적이라고 할 수 있다.
애니메이션 효과를 줘서 요소가 이동할 때 1px 단위마다 매번 reflow와 repaint가 일어날 경우에는 상당한 비용이 소모된다. 이런 경우에는 transform을 사용해서 컴포지팅 작업만 진행이 된다면 브라우저에 훨씬 부담이 덜어진다.
💡
reflow, repaint, 컴포지팅을 일으키는 css 속성을 아래의 사이트에서 확인해 보자.
 
사용자 경험(UX)를 강화하기 위해서는 응답 속도가 중요하다는 것은 이미 충분히 알려진 사실이다. 이런 응답 속도를 개선하기 위해서는 브라우저 렌더링 최적화가 필수적이다. 따라서 브라우저 렌더링 과정을 충분히 이해하고 최적화를 고려해야 한다.