브라우저란 웹에서 페이지를 찾아서 보여주고, 사용자가 하이퍼링크를 통해 다른 페이지로 이동할 수 있도록 하는 프로그램이라고 설명할 수 있다.
브라우저는 유저가 선택한 이미지, 비디오 등의 다양한 컨텐츠 요소를 서버로 부터 받아와서 렌더링 과정을 통해 유저에게 보여주게 된다.
사용자 인터페이스(UI) : 요청한 페이지를 보여주는 창을 제외한 모든 부분으로 주소 표시줄, 이전/다음 버튼, 북마크 메뉴등이 이에 해당한다.
브라우저 엔진 : 사용자 인터페이스와 렌더링 엔진 사이의 동작을 제어한다
렌더링 엔진 : 요청한 컨텐츠를 표시한다. 만약 HTML을 요청하면 HTML과 CSS를 파싱(해석)하여 화면에 표시한다
렌더링 엔진은 통신으로부터 요청한 문서의 내용을 얻는 것으로 시작하는데 문서의 내용은 보통 8KB 단위로 전송된다.
통신 : HTTP 요청과 같은 네트워크 호출에 사용된다. 이것은 플랫폼의 독립적인 기능이고 각 플랫폼의 하부에서 실행된다
UI 백엔드 : 콤보박스나 글 입력 폼등의 기본적인 장치를 그린다. 플랫폼에서 명시하지 않은 인터페이스로 OS 사용자 인터페이스 체계를 사용한다
자바스크립트 해석기 : 자바스크립트 코드를 해석하고 실행한다
자료 저장소 : 자료를 저장하는 계층으로 쿠키나 로컬 스토리지등의 자료가 저장되는 저장소이다. 이는 하드디스크에 저장되며 HTML명세등도 이곳에 저장된다
렌더링 엔진은 HTML 문서를 파싱하고 "콘텐츠 트리" 내부에서 태그를 DOM 노드로 변환한다. 그 다음 외부 CSS 파일과 함께 포함된 스타일 요소도 파싱한다. 스타일 정보와 HTML 표시 규칙은 "렌더 트리"라고 부르는 또 다른 트리를 생성한다.
렌더 트리는 색상 또는 면적과 같은 시각적 속성이 있는 사각형을 포함하고 있는데 정해진 순서대로 화면에 표시된다.
렌더 트리 생성이 끝나면 배치가 시작되는데 이것은 각 노드가 화면의 정확한 위치에 표시되는 것을 의미한다. 다음은 UI 백엔드에서 렌더 트리의 각 노드를 가로지르며 형상을 만들어 내는 그리기 과정이다.
일련의 과정들이 점진적으로 진행된다는 것을 아는 것이 중요하다. 렌더링 엔진은 좀 더 나은 사용자 경험을 위해 가능하면 빠르게 내용을 표시하는데 모든 HTML을 파싱할 때까지 기다리지 않고 배치와 그리기 과정을 시작한다. 네트워크로부터 나머지 내용이 전송되기를 기다리는 동시에 받은 내용의 일부를 먼저 화면에 표시하는 것이다.
브라우저가 페이지를 렌더링하려면 가장 먼저 받아온 HTML 파일을 해석해야한다. Parsing 단계는 HTML 파일을 해석하여 DOM(Document Object Model) Tree를 구성하는 단계이다.
파싱 중 HTML에 CSS가 포함되어 있다면 DOM 생성을 일시중단하고 CSSOM(CSS Object Model) Tree 구성 작업을 진행한다.
이후 CSS 파싱을 전부 완료한 뒤에 다시 HTML 을 파싱해 DOM 생성을 재개한다.
script 태그를 만나면, 마찬가지로 HTML 파싱을 중단하고 자바스크립트 파일을 불러와 자바스크립트 코드를 파싱한다. 자바스크립트 엔진을 이를 해석해, AST(추상적 구문 트리) 를 생성한다. 그리고 AST 를 기반으로 인터프리터가 실행할 수 있는 중간 코드인 바이트 코드를 생성해 실행한다.
Style 단계에서는 Parsing 단계에서 생성된 DOM Tree와 CSSOM Tree를 매칭시켜서 Render Tree를 구성한다. Render Tree는 실제로 화면에 그려질 Tree이다.
예를 들면 Render Tree를 구성할때 visibility: hidden은 요소가 공간을 차지하고, 보이지만 않기 때문에 Render Tree에 포함이 되지만, display: none 의 경우 Render Tree에서 제외된다.
Layout 단계에서는 Render Tree를 화면에 어떻게 배치해야 할 것인지 노드의 정확한 위치와 크기를 계산한다.
루트부터 노드를 순회하면서 노드의 정확한 크기와 위치를 계산하고 Render Tree에 반영한다. 만약 크기 값을 %로 지정하였다면, Layout 단계에서 % 값을 계산해서 픽셀 단위로 변환한다.
Layout 과정이 일어나는 상황
background-color, visibility 와 같이 레이아웃에는 영향을 주지 않는 속성이 변경되었을 때는 layout과정을 수행할 필요가 없다.
visibility invisible 은 레이아웃 공간을 차지하기 때문에 reflow 의 대상이 된다. 하지만 display none 은 Layout 공간을 차지하지 않아 Render Tree 에서 아예 제외된다.
left, right, width, height 보다 transform을, visibility/display 보다 opacitiy를 사용하는 것이 성능 개선에 도움이 된다.
Paint 단계에서는 Layout 단계에서 계산된 값을 이용해 Render Tree의 각 노드를 화면상의 실제 픽셀로 변환한다. 이때 픽셀로 변환된 결과는 하나의 레이어가 아니라 여러 개의 레이어로 관리된다.
당연한 말이지만 스타일이 복잡할수록 Paint 시간도 늘어난다. 예를 들어, 단색 배경의 경우 시간과 작업이 적게 필요하지만, 그림자 효과는 시간과 작업이 더 많이 필요하다.
Composite 단계에서는 Paint 단계에서 생성된 레이어를 합성하여 실제 화면에 나타낸다. 우리는 화면에서 웹 페이지를 볼 수 있다.