사용자 인터페이스 (User Interface) : 웹 페이지를 제외하고 사용자와 상호작용
브라우저 엔진 (Browser Engine) : 유저 인터페이스와 렌더링 엔진을 연결
렌더링 엔진 (Rendering Engine) : HTML과 CSS를 파싱하여 요청한 웹 페이지를 표시
통신 (Networking) : 네트워크 요청 수행
자바스크립트 해석기 (Javascript Interpreter) : 자바스크립트 코드 실행
UI 백엔드 (UI Backend) : 체크박스, 버튼같은 기본적인 위젯을 그려주는 파트
자료 저장소 (Data Persistance) : localStorage, Cookie 등의 보조 기억장치에 데이터를 저장
각 브라우저마다 상이한 렌더링 엔진을 갖고 있다.
Safari : Webkit
Firefox : Gecko
Chrome : Blink
렌더링 엔진의 동작 과정은 Ciritcal Rendering Path라고 하며 다음과 같다.
네트워크 통신을 통해 다음과 같은 HTML 문서를 받아왔다고 가정하자.
<html>
<head>
<title>Understanding the Critical Rendering Path</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<header>
<h1>Understanding the Critical Rendering Path</h1>
</header>
<main>
<h2>Introduction</h2>
<p>Lorem ipsum dolor sit amet</p>
</main>
<footer>
<small>Copyright 2017</small>
</footer>
</body>
</html>
먼저 HTML 코드는 어휘 분석을 통해 HTML5 표준에 지정된 고유한 토큰으로 변환된다.
예를 들어, <html>
를 만나면 html 시작 토큰을 생성하고, <head>
를 만나면 역시 <head>
시작 토큰을 생성한다. 이후 <head>
종료 토큰을 생성하고, <body>
태그의 시작 태그 생성, <h1> <p> <span>
등의 시작 토큰, Text 토큰, <body>
태그의 종료 토큰, 마지막으로 <html>
의 종료 토큰을 생성한다.
이후 브라우저의 렉싱 과정을 통해 토큰이 해당 속성과 규칙을 정의하는 노드 객체로 변환된다. 이후 각 노드 객체가 서로 연관성을 가질 수 있도록 트리 구조를 생성하는데, 이게 바로 DOM Tree 이다.
브라우저는 HTML 문서를 파싱하는 과정에서 자바스크립트나 CSS같이 추가로 필요한 파일들을 요청하기도 한다.
HTML을 통해 DOM 트리를 생성하는 과정과 비슷하게, CSS로는 CSSOM 트리를 생성한다. CSSOM은 DOM이 화면에 어떻게 표시될 지 알려주는 역할을 한다.
다음과 같은 CSS 파일이 있을 때
body { font-size: 18px; }
header { color: plum; }
h1 { font-size: 28px; }
main { color: firebrick; }
h2 { font-size: 20px; }
footer { display: none; }
이처럼 CSSOM 트리를 생성한다. DOM 트리와 마찬가지로 위에서 아래로 내려오는 구조 즉, 트리 구조이기 때문에, 부모 노드에 적용된 속성은 자식 요소들에게도 전파되어 적용된다.
HTML 문서를 파싱하다 <script>
태그를 만나서 자바스크립트가 실행되면, HTML 문서 파싱은 중단된다. 따라서 javascript는 파서 차단 리소스라고도 한다.
이때 javascript로 파싱이 중단되는 것을 막고 싶다면 async 속성 등을 통해 비동기적으로 설정할 수 있다.
렌더링 엔진은 DOM 트리와 CSSOM 트리르 합쳐서 렌더 트리 (Render Tree)를 생성한다.
렌더 트리에는 화면에 표시되어야 할 모든 노드의 컨텐츠, 스타일 정보가 포함되어있다.
meta
태그 또는 display: none
속성을 가진 요소들은 렌더와 관련되어있지 않기 때문에 렌더 트리에 포함되지 않는다.렌더 트리가 생성되면 레이아웃 과정을 거친다. 레이아웃은 다른 말로 Reflow 라고도 한다.
뷰포트 내에서 요소들에 정확한 위치와 크기를 계산하는 과정이다. 박스 모델에 따라서 텍스트나 요소의 박스가 화면에서 차지하는 영역이나 여백, 스타일 속성 등이 계산된다.
이때 CSS에서 % 또는 em 같은 상대적인 단위를 사용했을 경우, 화면의 뷰포트에 맞춰서 픽셀 단위로 변환된다.
이 레이아웃 과정에서 렌더링 엔진이 각 요소들이 어떻게 생겼고 또 어떻게 보여 줄지 파악하면, Paint (페인트) 과정을 통해 화면에 실제 픽셀로 그려준다. 이를 통해 렌더 트리에 포함된 텍스트, 이미지 등이 실제 픽셀로 그려진다.
사용자의 동작으로 인해 자바스크립트가 실행되어 CSS가 변경되거나 애니메이션 재생이 일어나는 경우에 렌더링 엔진이 대처하는 과정은 크게 3가지로 나눌 수 있다.
주로 요소의 크기나 위치가 바뀔 때 또는 브라우저 창 크기가 바뀔 때 다시 발생한다.
레이아웃의 수치를 다시 계산해서 배치를 해야하기 때문에 레이아웃 -> 페인팅 -> 레이어 합성 과정을 거쳐야한다.
주로 배경 이미지나 텍스트 색상, 그림자 등과 같이 레이아웃의 수치를 변화시키지 않는 스타일의 변경이 일어났을 때 발생한다.
레이어는 페인팅할 영역을 나누어놓는 것을 의미한다.
크롬의 경우 레이아웃 과정 이후에 정해진 기준이나 필요에 의해 브라우저가 레이어를 생성한다. 그리고 렌더 트리에 있는 노드 객체들은 이 레이어에 포함된다. 이러한 레이어는 트리 형태로 구성된다.
렌더링 엔진은 이 레이어를 프린팅하여 하나의 비트맵으로 합성하고 페이지를 완성한다.
이 케이스의 경우 레이아웃과 페인팅 과정을 수행하지 않고 레이어의 합성만 발생하기 때문에 성능상으로 가장 큰 이점을 갖는다.