Web_Miscellaneous / 브라우저 / 2.1 브라우저 렌더링 원리
2.1브라우저 렌더링 원리
브라우저 렌더링 원리에 관하여
요약
브라우저는 화면에 나타나는 요소를 렌더링 할 때, 렌더링 엔진(Blink, Webkit 등)을 사용함. 렌더링 엔진이 html, css, javascript로 렌더링 할 때 CRP(Critical Rendering Path)라는 프로세스를 사용
- html 파싱 후, DOM 트리 구축
- css 파싱 후, CSSOM 트리 구축
- javascript 실행(html 중간에 script가 있으면 html 파싱 중단)
- DOM과 CSSOM 조합하여 렌더 트리 구축
- 뷰 포트 기반으로 렌더트리의 각 노드가 가지는 위치/크기 계산(layout 단계)
- 계산한 위치/크기를 기반으로 화면에 그림(paint 단계)
1. 브라우저의 주요 기능
- 브라우저란 ? : (웹) 브라우저는 World Wide Web(인터넷)으로부터 정보 자원을 가져오고 보여주는 등의 활동을 하기 위해 만들어진 클라이언트-사이드 소프트웨어 애플리케이션.
- 사용자가 선택한 자원을 서버에 요청하고 브라우저에 표시
- 여기서 자원은 주로 html문서지만 pdf, 이미지 또는 그 외일 수도 있음
- 자원의 주소는 URI(Uniform Resource Identifier)에 의해 정해짐
- 브라우저는 html 파일을 해석하는데 있어 html과 css 명세에 따라 표시
- 이 명세는 W3C(World Wide Web Consortium)에서 정함
- 대부분의 브라우저는 아래의 기능들 공유
- URI를 입력할 수 있는 주소표시줄
- 이전 버튼/다음 버튼
- 북마크
- 새로 고침/현재 문서 로드 중단
- 홈
- 위 기능들은 표준 명세에 따른게 아니라 수년간 경쟁업체를 서로 모방하며 이른 것.
- html5 명세는 주소 표시줄, 상태 표시줄, 도구 모음만 명시
2. 브라우저의 기본 구조
- 사용자 인터페이스 : 주소 표시줄, 이전/다음 버튼, 북마크 메뉴 등 요청한 페이지를 보여주는 창 제외 나머지 모든 부분
- 브라우저 엔진 : 네트워크 요청, 보안, 네비게이션 관리 등 브라우저 전반 제어(렌더링 엔진을 포함하는 개념)
- 레이아웃, 렌더링 외에도 문서들 간의 보안 정책을 강제하며 페이지 스크립트에 노출되는 DOM 자료 구조를 구현
- 렌더링 엔진(=layout engine) : 요청한 콘텐츠를 표시. 파싱, 레이아웃 배치 등 시각적인 부분 만드는 엔진
- 예를 들어 html을 요청하면 html과 css를 파싱하여 화면에 표시
- 통신 : http 요청과 같은 네트워크 호출에 사용
- UI 백엔드 : 콤보 박스와 창 같은 기본적인 장치를 그림
- 자바스크립트 해석기
- 자료 저장소 : 쿠키 등 모든 종류의 자원을 하드 디스크에 저장
브라우저 아키텍처. 브라우저는 렌더링 엔진, 통신, UI 백엔드, 자바스크립트 해석기, 자료 저장소 등 여러 컴포넌트로 구성되어 있음.
cf) 크롬은 대부분의 브라우저들과 달리 각 탭마다 별도의 렌더링 엔진 인스턴스를 유지.(각 탭이 독립된 프로세스로 처리)
3. 렌더링 엔진
- 요청 받은 내용을 브라우저 화면에 표시
- Gecko : 파이어폭스에서 사용
- Webkit : 사파리에서 사용
- Blink: 크롬, 엣지에서 사용
- 기본 동작 과정은 아래와 같음

- html 문서를 파싱하고 콘텐츠 트리 내부에서 태그를 DOM 노드로 변환.
- 외부 CSS파일과 함께 포함된 스타일 요소도 파싱
- 이 스타일 정보와 html 표시 규칙은 “렌더 트리”라고 부르는 또다른 트리 생성
- 렌더 트리는 색상/면적 등 시각적 속성이 있는 사각형 포함.
- 렌더 트리 생성이 끝나면 배치 시작(노드를 화면의 정확한 위치에 표시)
- UI 백엔드에서 렌더 트리의 각 노드를 가로지르며 형상을 그림
- 아래는 webkit 동작 과정
webkit 렌더링 과정. 브라우저는 렌더링 엔진, 통신, UI 백엔드, 자바스크립트 해석기, 자료 저장소 등 여러 컴포넌트로 구성되어 있음.
4. 파싱과 DOM 트리 구축
- 파싱 : 브라우저가 코드를 이해하고 사용할 수 있는 구조로 변환하는 것
- 파싱한 결과는 보통 문서 구조를 나타내는 노드 트리
- 이 노드 트리들을 parse tree 또는 syntax tree라고 부름
- 문맥 자유 문법 : 파싱할 수 있는 모든 형식은 정해진 용어와 구문 규칙(BNF라고 부르는 규칙)에 따라야함(인간의 언어는 BNF에 따르지 않아 기계적 파싱이 불가)
- BNF: https://ko.wikipedia.org/wiki/배커스-나우르_표기법 (아래는 예시)
BNF 예시. 브라우저는 렌더링 엔진, 통신, UI 백엔드, 자바스크립트 해석기, 자료 저장소 등 여러 컴포넌트로 구성되어 있음.
- BNF: https://ko.wikipedia.org/wiki/배커스-나우르_표기법 (아래는 예시)
- 파싱한 결과는 보통 문서 구조를 나타내는 노드 트리
- 파서-어휘 분석기 조합
- 파싱은 어휘 분석/구문 분석 2가지로 구분 할 수 있음
- 어휘 분석(토큰 변환) : 자료를 토큰으로 분해
- 토큰: 인간으로 따지면 사전에 등장하는 모든 단어. 유효하게 구성된 단위의 집합체.
- 어휘: 정규 표현식(Regex)으로 보통 표현됨
- 구문 분석 : 언어의 구문 규칙(BNF라고 부르는 형식)을 적용
- 어휘 분석(토큰 변환) : 자료를 토큰으로 분해
- 파싱은 어휘 분석/구문 분석 2가지로 구분 할 수 있음
- 파싱 과정은 보통 파서가 어휘 분석기로부터 새 토큰을 받아 구문 규칙과 일치하는지 확인하고,
- 규칙에 맞으면 노드가 파싱 트리에 추가되고 파서가 또 다른 토큰을 요청하고
- 규칙에 맞지 않으면 파서는 토큰을 내부적으로 저장하고 토큰과 일치하는 규칙이 발견될 때까지 요청. 맞는 규칙이 없는 경우 예외로 처리
- 변환 : 파서 트리는 최종 결과물이 아님. 파싱은 문서를 다른 양식으로 변환하는 것인데 소스 코드를 기계 코드로 만드는 컴파일러가 있어 파싱 트리 생성 후 이를 기계 코드 문서로 변환
- 파서의 종류
- 하향식 파서: 구문의 상위 구조로부터 일치하는 부분을 찾음
- 상향식 파서: 낮은 수준에서 점차 높은 수준으로 찾음 ⇒ 이동-감소 파서라고도 부름(점차 이동하며 남는 파싱 대상이 감소하기 때문)
- 파서 자동 생성
- 파서 생성기: 파서를 생성해 줄 수 있는 도구. 언어에 어휘/구문규칙 같은 문법을 부여하면 동작하는 파서를 만들어줌
- webkit은 어휘 생성을 위한 Flex와 파서 생성을 위한 Bison을 사용
- Flex: 토큰의 정규 표현식 정의를 포함하는 파일을 입력 받음
- Bison: BNF 형식의 언어 구문 규칙을 입력 받음
- webkit은 어휘 생성을 위한 Flex와 파서 생성을 위한 Bison을 사용
- 파서 생성기: 파서를 생성해 줄 수 있는 도구. 언어에 어휘/구문규칙 같은 문법을 부여하면 동작하는 파서를 만들어줌
- HTML 파서: html 마크업을 파싱 트리로 변환
- html 문법은 문맥 자유 문법이 아님 : 모든 전통적인 파서는 html에 적용할 수 없음. html 정의를 위한 공식적 형식으론 DTD(문서 형식 정의)가 있지만 이건 문맥 자유 문법이 아님.
- html은 암묵적으로 태그에 대한 생략이 가능. (유연한 문법) ⇒ 웹 제작자의 실수를 너그럽게 용서하고 편하게 만들어주지만, 대신 공식적인 문법으로 작성하기 어려움
- DOM : “파싱 트리”는 DOM 요소와 속성 노드의 트리로서 출력 트리가 됨. DOM은 문서 객체 모델(Document Object Model)의 준말.
- html 문서의 객체 표현
- 외부를 향하는 자바스크립트와 같은 html 요소의 연결 지점.
- 트리의 최상위 객체는 문서
- DOM은 마크업과 1:1 관계임
예를 들면,
html
<html> <body> <p>Hello World</p> <div><img src="example.png" /></div> </body> </html>
- html 문법은 문맥 자유 문법이 아님 : 모든 전통적인 파서는 html에 적용할 수 없음. html 정의를 위한 공식적 형식으론 DTD(문서 형식 정의)가 있지만 이건 문맥 자유 문법이 아님.
위 코드는 아래의 DOM 트리로 변환 가능

- 파싱 알고리즘 : html은 일반적인 하향식/상향식 파서로 파싱이 안되는데, 이유는
- 언어의 너그러운 속성
- html 오류에 대한 브라우저의 관용
- 변경에 의한 재파싱. 일반적으로 소스는 파싱하는 동안 변하지 않지만 html에서는 스크립트 태그가 토큰 추가가 가능해서 입력 과정에서 파싱 수정.
- 따라서 일반적인 파싱 기술을 사용할 수 없기에 html은 파싱을 위한 별도의 파서를 필요로 함. 이는 브라우저 엔진들(Blink, Gecko, Webkit)등에 있음
- 토큰화 / 트리 구축 이렇게 2단계
- 토큰화 : 어휘 분석. 입력값을 토큰으로 파싱(html에선 시작 태그, 종료 태그, 속성 이름과 속성 값) ⇒ 토큰을 인지하면 트리 생성자로 넘김
토큰화 과정
- 토큰화 : 어휘 분석. 입력값을 토큰으로 파싱(html에선 시작 태그, 종료 태그, 속성 이름과 속성 값) ⇒ 토큰을 인지하면 트리 생성자로 넘김
- 토큰화 / 트리 구축 이렇게 2단계
- 트리 구축 알고리즘
- 파서가 생성되면 문서 객체가 생성됨
- 트리 구축이 진행되는 동안 문서 최상단 객체에서는 DOM 트리가 수정되고 요소가 추가됨
- 토큰화에 의해 발행된 각 노드는 트리 생성자에 의해 처리됨
- DOM트리에 요소를 추가하는 것이 아니라면 열린 요소는 스택(임시 버퍼 저장소)에 추가됨
- 스택에서 부정확한 중첩과 종료되지 않은 태그를 교정
- 파싱이 긑나면, 브라우저는 문서와 상호작용 가능
- 문서 파싱 이후에 실행되어야 하는 ‘지연’모드 스크립트 파싱 시작
- 문서 상태 ‘완료’, ‘로드’이벤트 발생
5. CSS 파싱
css는 html과 달리 문맥 자유 문법이기에 일반적인 파서로 파싱이 가능
- 스크립트와 스타일 시트의 진행 순서
- 스크립트 : 웹은 파싱과 실행이 동시에 수행되는 동기화(synchronous) 모델
- 제작자는 파서가
<script>
태그를 만나면 즉시 파싱하고 실행하기를 기대 - 스크립트가 실행되는 동안 문서의 파싱은 중단(스크립트가 외부에 있는 경우에도 네트워크로부터 자원을 가져오는 동안 파싱 중단)
- 스크립트를 defer로 표시할 수 있는데 이러면 문서 파싱이 중단되지 않고 문서 파싱부터 완료한 후 스크립트를 실행
- html5에서는 스크립트를 asynchronous로 처리하는 속성을 추가했기 때문에 별도의 맥락에 의해 파싱되고 실행
- 제작자는 파서가
- 예측 파싱 : 브라우저가 지원하는 최적화 기능 중 하나로, 스크립트를 실행하는 동안 다른 스레드가 네트워크로부터 다른 자원을 찾아 내려받고 문서의 나머지 부분 파싱
- DOM 트리를 수정하진 않음.(이건 메인 파서의 일) 외부 스크립트, 외부 스타일 시트, 외부 이미지 등 참조된 외부 자원을 파싱
- 스타일 시트: DOM 트리를 변경하지 않기에 문서 파싱을 기다리거나 중단할 이유가 없음.
- 단, 스크립트가 문서를 파싱하는 동안 스타일 정보를 요청한다면 스크립트 실행을 중단하는 등의 조치를 브라우저가 취함
- 렌더 트리 구축
- DOM 트리가 구축되는 동안 브라우저는 렌더 트리를 구축
- 표시해야 할 순서와 문서의 시각적인 구성 요소를 올바른 순서로 그리기 위함
- DOM 트리가 구축되는 동안 브라우저는 렌더 트리를 구축
- DOM 트리와 렌더 트리의 관계
- 렌더 트리의 구성 요소인 렌더러는 DOM 요소에 부합하지만 1:1 대응은 아님(ex. head 요소 같은 비시각적 DOM 요소는 렌더 트리에 들어가지 않으며, display 속성이 none이면 트리에 나오지 않음)
- 스타일 계산
- 렌더 트리 구축을 위해선 렌더 객체들 각각의 시각적 속성에 대한 계산이 필요
- 인라인 스타일 요소 + html의 시각적 속성(css 스타일로 변환되어 적용)
- 스타일 규칙을 적용하는 것은 계층 구조를 파악해야하는 꽤 복잡한 다단계 규칙을 지켜야함(div div div 이런 식으로 중첩되었을 경우 등)
- 렌더 트리 구축을 위해선 렌더 객체들 각각의 시각적 속성에 대한 계산이 필요
- 스크립트 : 웹은 파싱과 실행이 동시에 수행되는 동기화(synchronous) 모델