브라우저는 널리 사용되는
소프트웨어
다. 이 글을 통해 브라우저 주소 창에google.com
을 입력했을 때 브라우저가 어떻게 동작해서 구글 페이지가 화면에 보이게 되는지 알아보자.
빠른 사이트는 더 나은 사용자 경험을 제공한다. 사용자는 로딩 속도가 빠르고 상호 작용하기 쉬운 콘텐츠가 포함된 웹 경험을 원하고 기대한다.
웹 성능에 있어서 대기 시간
과 브라우저가 단일 스레드라는 사실
에 대해 이해하는 것이 중요하다.
웹 페이지를 로드 첫 번째 단계
사용자가 주소 표시줄에 URL을 입력
하고, 링크를 클릭
하고, 양식을 제출
하고, 기타 작업을 수행하여 페이지를 요청할 때마다 발생한다.
웹 페이지 탐색의 첫 번째 단계는 해당 페이지의 자산이 있는 위치를 찾는 것
사이트를 방문한 적 없다면 브라우저는 DNS 조회를 요청한다.
1. 네임 서버에 도메인 입력
2. 네임 서버는 IP 주소로 응답
한 번의 요청 후 IP는 한동안 캐시
될 가능성이 높으며,
다음 조회부터는 네임 서버에 연결하는 대신 캐시
에서 IP 주소를 검색해 요청 속도를 높인다.
DNS 조회는 일반적으로 페이지 로드에 대해 각각의 호스트 이름당 한 번만 수행하면 된다.
IP 주소를 알게 되면 브라우저는 TCP 3-way handshake(SYN, SYN-ACK, ACK) 메커니즘
을 통해 서버에 대한 연결을 설정한다. 이를 통해 브라우저와 웹 서버가 데이터 전송 전에 HTTPS
를 통해 네트워크 TCP 소켓 연결의 매개변수를 협상할 수 있다.
HTTPS
를 통해 보안 연결을 설정하려면 또 다른 handshake가 필요하다.
이 handshake를 TLS 협상
이라고 하며,
통신을 암호화하는데 사용할 암호를 결정하고 서버를 확인해서
실제 데이터 전송을 시작하기 전에 보안 연결이 설정되어 있는지 확인한다.
웹 브라우저는 사용자가 그래픽 사용자 인터페이스
를 통해 웹 페이지
또는 기타 온라인 콘텐츠에 액세스하고 표시할 수 있도록 하는 소프트웨어 응용 프로그램이다.
브라우저의 주요 기능은 사용자가 선택한 자원(HTML, PDF, 이미지 등)을 서버에 요청하고 브라우저에 표시하는 것이다.
자원의 주소는 URI(Uniform Resource Identifier)에 의해 정해진다.
브라우저는 HTML과 CSS 명세에 따라 HTML 파일
을 해석해서 표시하는데 이 명세는 웹 표준화 기구(World Wide Web Consortium, W3C)
에서 정한다.
브라우저의 UI(사용자 인터페이스)는 서로 닮아 있는데 다음과 같은 요소들이 일반적이다.
브라우저의 주요 구성 요소는 다음과 같다.
웹 데이터 베이스
가 정의되어 있다.크롬은 대부분의 브라우저와 달리 각 탭마다 별도의 렌더링 엔진 인스턴스를 유지한다.
즉, 각 탭은 독립된 프로세스로 처리된다.
사용자가 특정 문서를 요청하면 렌더링 엔진은 요청받은 HTML 및 XML 문서와 이미지 등을 브라우저 화면에 표시할 수 있다. 렌더링 엔진은 네트워킹 계층에서 해당 특정 문서의 콘텐츠를 8KB 청크로 수신하기 시작한다.
플러그인
,브라우저 확장 기능
을 이용해 PDF 등도 표시할 수 있다.
파이어폭스 : 모질라 의 게코(Gecko)엔진
인터넷 익스플로러: 트라이던트(Trident)엔진
사파리, 크롬(iOS) : 웹킷(Webkit)엔진
(최초 리눅스 플랫폼에서 동작하기 위해 제작된 오픈소스 엔진)
크롬, 오페라 : 블링크(blink)
엔진
모든 브라우저에는 고유한 렌더링 엔진이 있다. 따라서 자연스럽게 모든 브라우저에는 사용자 화면에서 웹 페이지를 해석하는 고유한 방법이 있다. 여기에서 웹 개발자에게 웹 사이트의 브라우저 간 호환성과 관련하여 문제가 발생한다.
렌더링 엔진은 통신으로부터 요청한 문서의 내용을 얻는 것으로 시작한다.
TCP 느린시작 / 14kb
콘텐츠의 첫 번째 응답 패킷(청크)은 일반적으로 14kb의 데이터다.
네트워크 연결 속도의 균형을 맞추기 위해 느린 시작은 네트워크의 최대 대역폭을 결정할 수 있을 때까지 전송되는 데이터의 양을 점진적으로 증가시킨다.혼잡 제어
하드웨어 및 네트워크 조건에 따라 연결 용량을 제한하고 패킷 및 ACK 흐름을 사용해 전송 속도를 결정한다.
다음은 렌더링 엔진의 기본적인 동작 과정이다.
요청된 HTML 페이지는 렌더링 엔진
에 의해 외부 CSS 파일 및 스타일 요소를 포함한 청크로 구문 분석
된다. 그런 다음 HTML 요소는 DOM 노드로 변환되어 콘텐츠 트리
또는 DOM 트리
를 형성한다.
콘텐츠 트리
내부에서 태그
를 DOM 노드로 변환동시에 브라우저는 렌더 트리
를 생성한다. 이 트리에는 스타일 정보와 요소가 표시되는 순서를 정의하는 시각적 지침이 모두 포함된다. 렌더 트리는 콘텐츠가 원하는 순서로 표시되도록 한다.
렌더 트리는 레이아웃(배치) 프로세스
를 거친다. 렌더 트리가 생성될 때 위치 또는 크기 값이 할당되지 않는다. 원하는 위치를 평가하기 위한 값을 계산하는 전 과정을 레이아웃(배치) 과정이라고 한다. 이 과정에서 모든 노드에 정확한 좌표가 할당된다. 이렇게 하면 모든 노드가 화면의 정확한 위치에 표시된다.
마지막 단계는 화면을 그리는 것
이다. 여기서 렌더 트리가 탐색되고 렌더러의 paint() 메서드가 호출되어 UI 백엔드 레이어를 사용하여 화면의 각 노드를 그린다.
렌더링 엔진은 좀 더 나은 사용자 경험을 위해 가능하면 빠르게 내용을 표시한다.
그러기 위해 모든 HTML을 파싱할 때까지 기다리지 않고 배치와 그리기를 시작한다.
즉, 네트워크로부터 나머지 내용이 전부 전송되기를 기다리면서 받은 내용의 일부를 먼저 화면에 표시한다.
과정 | 게코 | 웹킷 |
---|---|---|
시각적으로 처리되는 트리 | 형상 트리(frame tree, 각 요소는 frame) | 렌더 트리(render tree, 각 요소는 render object) |
요소 배치 | 리플로(reflow) | 배치(layout) |
DOM 노드와 시각 정보 연결 | 콘텐츠 싱크(content sink) | 어태치먼트(attachment) |
브라우저가 데이터의 첫 번째 청크를 수신하면 수신된 정보의 구문 분석을 시작할 수 있다.
구문 분석은 브라우저가 네트워크를 통해 수신한 데이터를 DOM 및 CSSOM으로 변환하는 단계이며, 이것은 렌더러가 페이지를 화면에 그리는 데 사용한다.
DOM : 브라우저에 대한 마크업의 내부 표현. DOM도 노출되며 JavaScript의 다양한 API를 통해 조작할 수 있다.
노드 트리(파싱 트리, 문법 트리)
파싱은 어휘 분석과 구문 분석으로 구분할 수 있다.
파서가 하는 일은 두가지가 있다.
파싱 과정은 반복된다.
파서 트리는 최종 결과물이 아니다.
파싱은 보통 문서를 다른 양식으로 변환(컴파일)하는데,
컴파일러
는 파싱 트리 생성 후 이를 기계 코드 문서로 변환한다.
예) 수학 표현식 2+3-1
어휘: 수학 언어는 정수, 더하기 기호, 빼기 기호를 포함한다.
구문
1. 언어 구문의 기본적인 요소는 표현식, 항, 연산자이다.
2. 언어에 포함되는 표현식의 수는 제한이 없다.
3. 표현식은 "항" 뒤에 "연산자" 그 뒤에 또 다른 항이 따르는 형태로 정의한다.
4. 연산자는 더하기 토큰 또는 빼기 토큰이다.
5. 정수 토큰 또는 하나의 표현식은 항이다.
2+3-1
에서
2
: 5번째 규칙
2+3
: 5, 3번째 규칙
2+3-1
: 5, 3번째 규칙
INTEGER : 0|[1-9][0-9]*
PLUS : +
MINUS : -
문맥 자유 문법
을 나타내기 위해 만들어진 표기법)에 따라 정의한다.expression := term operation term
operation := PLUS | MINUS
term := INTEGER | expression
파서 생성기
웹킷의 파서
HTML 파서는 HTML 마크업을 파싱 트리로 변환한다.
HTML 어휘와 문법은 W3C에 의해 명세로 정리되어 있다.
HTML 정의를 위한 공식적인 형식으로 DTD(문서 형식 정의)가 있지만, 이것은 문맥 자유 문법이 아니다.
HTML은 XML과 유사하지만, 보다 "유연"하고 "너그러운" 문법이기 때문이다.
HTML 정의는 DTD 형식 안에 있는데 SGML 계열 언어의 정의를 이용한 것이다.
이 형식은 허용되는 모든 요소와 그 속성, 중첩 구조에 대한 정의를 포함한다.
DTD는 오래된 콘텐츠에 대한 하위 호환성을 위해 오래된 마크업을 지원한다.
파싱 트리는 DOM 요소와 속성 노드의 트리로서 출력 트리가 된다.
DOM은
트리가 DOM 노드를 포함한다 === DOM 접점의 하나를 실행하는 요소를 구성한다
HTML은 일반적인 하향식/상향식 파서로 파싱이 안된다. 이유는 다음과 같다.
document.write
을 포함하고 있는 스크립트 태그는 토큰을 추가할 수 있기 때문에 입력 과정에서 파싱이 수정된다.그래서, 브라우저는 HTML 파싱을 위해 별도의 파서를 생성하는 단계를 진행한다.
알고리즘은 상태 기계다.
각 상태는 하나 이상의 연속된 문자를 입력 받아 이 문자에 따라 다음 상태를 갱신한다.
결과는 현재 토큰화 상태와 트리 구축 상태 영향을 받으므로, 같은 문자에 대해서도 결과가 다르게 나올 수 있음을 의미한다.
파서가 생성되면 문서 객체가 생성된다.
트리 구축이 진행되는 동안 문서 최상단에 DOM 트리가 수정되고 요소가 추가된다.
토큰화에 의해 생성된 각 노드는 트리 생성자에 의해 처리된다.
브라우저는 문서와 상호작용할 수 있게 된다.
문서 상태는 완료가 되고 로드 이벤트가 발생한다.
"Invalid Syntax" error : 브라우저가 모든 오류 구문을 교정하기 때문에 발생하는 에러
파서는 다음과 같은 오류들을 처리해야 한다.
<예시> 웹킷이 하는 일
1. <br>
을 </br>
로 내부적으로 처리해 브라우저 간 호환성을 높인다.
2. A stray <table>
: 테이블 중첩 관계가 잘못 되었을 때, 형제 관계로 만든다.
3. 중첩된 <form>
: 안쪽의 <form>
은 무시한다.
4. 태그의 중첩이 너무 깊을 때 : 최대 20개의 중첩만 허용하고 나머지는 무시한다.
5. 잘못 닫힌 <html>
, <body>
태그 : <body>
태그를 닫지 않고 종료를 위한 end()
를 호출한다.
CSS는 문맥 자유 문법이다. 즉 파서 유형을 이용한 파싱이 가능하다.
웹킷은 CSS 파일로부터 자동으로 파서를 생성하기 위해 플렉스와 바이슨 파서 생성기(상향식 이동 감소 파서 생성)를 사용한다.
웹은 파싱과 동시에 수행되는 동기화 모델이다.
스크립트가 실행되는 동안 문서 파싱은 중단된다.
스크립트를 지연(defer)으로 표시할 수 있는데, 이 경우 문서 파싱은 중단되지 않고 문서 파싱 완료 후 스크립트가 실행된다.
HTML5는 스크립트를 비동기로 처리하는 속성을 추가했기 때문에 별도의 맥락에서 파싱되고 실행된다.
웹킷과 파이어폭스는 예측 파싱과 같은 최적화를 지원한다.
- 스크립트 실행 중 다른 스레드는 문서의 나머지를 파싱한다.
- 자원을 병렬로 연결해 받고, 속도를 개선한다.- DOM 트리를 수정하지 않고 메인 파서의 일로 넘긴다.
- 외부 스크립트/스타일 시트/이미지 등 외부 자원만을 파싱한다.
스타일 시트는 DOM 트리를 변경하지 않으므로 문서 파싱을 기다리거나 중단할 필요가 없다.
스크립트가 문서 파싱 중 스타일 정보를 요청하는 경우?
DOM 트리가 구축되는 동안 브라우저는 렌더 트리를 구축한다.
목적 : 표시해야 할 순서와 문서의 시각적인 구성 요소(형상, 렌더러, 렌더 객체)로써 올바른 순서로 내용을 그려내기 위함렌더러는 자신과 자식 요소를 어떻게 배치하고 그려야 하는지 알고 있다.
렌더러는 DOM 요소에 부합하지만 1:1 대응 관계는 아니다.
파이어폭스의 프레젠테이션
웹킷의 어태치먼트
html태그와 body태그를 처리함으로써 렌더 트리 루트 구성
렌더 트리를 구축하려면 각 렌더 객체의 시각적 속성에 대한 계산이 필요하다.
스타일 계산의 어려움
1. 수 많은 스타일 속성에 대한 메모리 문제
2. 최적화되어 있지 않다면 각 요소에 할당된 규칙을 찾는 것은 성능 문제를 야기
3. 규칙을 적용하는 것은 계층 구조를 파악해야 하는 복잡한 규칙을 수반
스타일 문맥
트리가 작업량을 줄이는 방법
가장 구체적인 노드에 값을 추가하면 실제 값으로 변환하기 위해 추가적인 계산이 필요하다.
트리 노드에서 결과를 저장하므로 자식에게도 사용할 수 있다.
같은 트리 노드를 가리키는 형제 요소가 있는 경우 전체 스타일 문맥이 공유된다.
규칙 트리
스타일 규칙을 위한 방법
스타일 시트를 파싱한 후
규칙
은선택자
에 따라 여러 해시맵 중 하나에 추가된다.
아이디, 클래스 이름, 태그 이름을 사용한 맵
이 있고,일반적인 맵
이 있다.
이러한 최적화는 찾아야할 규칙의 95% 이상을 제거한다.
스타일 객체는 모든 CSS 속성을 포함하고 있는데, 어떤 규칙과도 일치하지 않는 일부 속성은 부모 요소의 스타일 객체로부터 상속받는다. 그 외 다른 속성들은 기본 값으로 설정된다.
문제는 하나 이상의 속성이 정의될 때 발생된다.
Cascade
- 브라우저 선언 (browser declarations)
- 중요도가 가장 낮다.
- 사용자 일반 선언 (user normal declarations)
- 저작자의 선언을 덮어쓸 수 있는 것은
!important
뿐이다.- 저작자 일반 선언 (author normal declarations)
- HTML 시각 속성은 CSS 속성 선언으로 변환되며 저작자 일반 선언 규칙으로 간주된다.
- 저작자 중요 선언 (author important declarations)
- 사용자 중요 선언 (user important declarations)
특정성(specificity)
선택자 특정성
선택자 없이 'style' 속성이 선언된 것이면 1을 센다. 그렇지 않으면 0을 센다. (=a)
선택자에 포함된 아이디 선택자 개수를 센다. (=b)
선택자에 포함된 속성 선택자(클래스 선택자와 속성 선택자)와 가상 클래스 선택자의 숫자를 센다. (=c)
선택자에 포함된 요소 선택자와 가상 요소 선택자의 숫자를 센다. (=d)
특정성의 값 = a-b-c-d 연결. 가장 높은 숫자에 의해 사용할 진법을 정한다.
규칙 정렬
맞는 규칙을 찾으면 cascade
규칙에 따라 정렬된다.
웹킷은 목록이 적으면 버블 정렬, 많으면 병합정렬을 사용하며
규칙에 ">" 연산자를 덮어쓰는 방식으로 정렬을 실행한다.
점진적 처리
웹킷은 @import
를 포함한 최상위 수준의 스타일 시트가 로드되었는지 표시하기 위해 플래그
를 사용한다.
DOM 노드와 시각정보를 연결하는 과정에서 스타일이 완전히 로드되지 않았다면 문서에 자리 표시자를 사용하고,
스타일 시트가 로드됐을 때 다시 계산한다.
렌더러가 생성되어 트리에 추가될 때 크기와 위치 정보는 없는데 이런 값을 계산하는 것을 배치 또는 리플로라고 부른다.
HTML
은 흐름 기반의 배치 모델을 사용하는데 이것은 보통 단일 경로를 통해 크기와 위치 정보를 계산할 수 있음을 의미한다. (왼쪽~오른쪽, 위~아래)
배치는 반복되며 HTML 문서의 <html>
요소에 해당하는 최상위 렌더러에서 시작된다.
배치는 프레임 계층의 일부 또는 전부를 통해 반복되고 각 렌더러에 필요한 크기와 위치 정보를 계산한다.
모든 렌더러는 "배치" 또는 "리플로" 메서드를 갖는데, 각 렌더러는 배치해야 할 자식의 배치 메소드를 불러온다.
전체를 다시 배치하지 않기 위해 브라우저는 dirty bit
를 사용한다. 렌더러는 다시 배치할 필요가 있는 변경 요소 또는 추가된 것과 그 자식 요소를 dirty
라고 표현한다.
dirty
와 children are dirty
플래그가 존재하는데, children are dirty
플래그는 자신을 제외하고 자식 가운데 적어도 하나를 다시 배치할 필요가 있다는 의미이다.
배치는 렌더러 트리 전체에서 일어날 수 있는데, 이것을 전역
배치라 하고, 다음과 같은 경우에 발생한다.
1. 글꼴 크기 변경과 같이 모든 렌더러에 영향을 주는 전역 스타일 변경
2. 화면 크기 변경에 의한 결과
배치는 dirty
렌더러가 배치되는 경우에만 점증되는데, 추가적인 배치가 필요하므로 약간의 손실이 발생할 수 있다.
점증 배치는 렌더러가 dirty
일 때 비동기적으로 일어난다.
예를 들어 네트워크로부터 추가 내용을 받아서 DOM 트리에 더해진 다음 새로운 렌더러가 렌더 트리에 붙을 때이다.
점증 배치는 비동기로 실행된다.
파이어폭스 : 리플로 명령을 쌓아놓고 스케줄러는 이 명령을 한꺼번에 실행
웹킷 : 점증 배치를 실행하는 타이머. 트리를 탐색해 dirty 렌더러를 배치
offsetHeight
같은 스타일 정보를 요청하는 스크립트는 동기적으로 점증 배치 실행배치가 크기 변경이나 렌더러 위치 변화 때문에 실행되는 경우 렌더러의 크기는 캐시로부터 가져온다.
배치는 보통 다음과 같은 형태로 진행된다.
1. 부모 렌더러가 자신의 너비를 결정
2. 부모가 자식을 확인 (자식 렌더러를 배치, 필요하다면 자식 배치를 호출해 자식의 높이 계산)
3. 부모는 자식의 누적 높이, 여백, 패딩을 사용해 자신의 높이 설정
4. dirty bit
플래그 제거
파이어폭스는 상태
객체를 배치(리플로)를 위한 매개 변수로 사용하는데, 상태는 부모 너비를 포함한다.
파이어폭스의 리플로 결과는 매트릭스 객체이며 높이가 계산된 렌더러를 포함한다.
렌더러의 너비는 포함하는 블록의 너비
, 렌더러의 너비
, 여백
, 테두리
를 이용해 계산된다.
배치할 필요가 있지만 너비가 고정된 경우 값은 캐시
에 저장된다.
렌더러가 배치되는 동안 줄을 바꿀 필요가 있을 때 배치는 중단되고 줄 바꿀 필요가 있음을 부모에 전달한다.
부모는 추가 렌더러를 생성하고 배치를 호출한다.
화면에 내용을 표시하기 위한 렌더 트리가 탐색되고 렌더러의
paint
메서드가 호출된다.
그리기는 UI 기반의 구성 요소를 사용한다.
배치와 마찬가지로 전역 또는 점증 방식으로 그리기 수행된다.
점증 그리기에서 일부 렌더러는 전체 트리에 영향을 주지 않는 방식으로 변경된다.
변경된 렌더러는 화면 위의 사각형을 무효화하는데 OS는 이것을 dirty
영역으로 보고 paint
이벤트를 발생시킨다. OS는 몇 개의 영역을 하나로 합치는 방법으로 효과적으로 처리하며, 크롬은 OS의 동작을 어느 정도 모방한다.
프레젠테이션은 이러한 이벤트를 듣고 렌더 최상위로 메시지를 전달하며,
트리는 적절한 렌더러에 이를 때까지 탐색되고 그려진다.
요소가 stacking contexts
에 쌓이는 순서와 같다.
블록 렌더러가 쌓이는 순서는 다음과 같다.
파이어폭스는 렌더 트리를 검토하고 그려진 사각형을 위한 표시 목록을 구성한다. 이러한 방법으로 트리는 여러 번 리페인팅하는 대신 한 번의 탐색으로 그려낸다.
파이어폭스는 다른 불투명 요소 뒤에 완전히 가려진 요소는 추가하지 않는 방법으로 최적화를 진행한다.
리페인팅 전에 웹킷은 기존의 사각형을 비트맵으로 저장해 새로운 사각형과 비교하고 차이가 있는 부분만 다시 그린다.
브라우저는 변경에 대해 최소한의 동작으로 반응하려고 노력한다.
- 요소의 색깔이 바뀌면 해당 요소의 리페인팅만 발생
- 요소의 위치가 바뀌면 요소와 자식, 형제의 리페인팅과 재배치 발생
- DOM 노드를 추가하면 노드의 리페인팅과 재배치 발생
- html요소의 글꼴 변경 등에서 캐시를 무효화하고 트리 전체 배치, 리페인팅 발생
렌더링 엔진은 통신을 제외한 거의 모든 경우 단일 스레드로 동작한다.
파이어폭스, 사파리 : 렌더링 엔진의 스레드는 브라우저의 주요한 스레드
크롬 : 탭 프로세스의 주요 스레드
브라우저의 주요 스레드는 이벤트 순환으로 처리 과정을 유지하기 위해 무한 순환된다.
배치와 그리기 같은 이벤트를 위해 대기하고 이벤트를 처리한다.
서식 구조가 표현되는 공간. 브라우저가 내용을 그리는 공간
기본적으로 투명해서 겹치는 경우 비쳐 보이고, 투명하지 않을 경우 정의한 색이 지정된다.
문서 트리에 있는 요소를 위해 생성되고 시각적 서식 모델에 따라 배치된 사각형 박스를 설명한다.
각 박스는 콘텐츠 영역과 패딩(Optional), 테두리, 여백이 있다.
박스의 유형은 display
속성(block
, inline
, none
)에 의해 결정된다.
위치를 결정하는 방법은 다음과 같은 세 가지이다.
1. Normal : 렌더 트리에서 객체의 자리가 DOM 트리의 자리와 같고 박스 유형, 면적에 따라 배치된다.
2. Float : 객체는 일반적인 흐름에 따라 배치된 다음 왼쪽이나 오른쪽으로 흘러 이동한다.
3. Absolute : 객체는 DOM 트리 자리와는 다른 렌더 트리에 놓인다
위치는 position
속성과 float
속성에 의해 결정된다.
static
(기본 값)과 relative
로 설정하면 일반적인 흐름에 따라 위치가 결정된다.absolute
와 fixed
로 설정하면 절대적인 위치가 된다.블록 박스: 브라우저 창에서 사각형 블록을 형성한다.
인라인 박스: 블록이 되지 않고 블록 내부에 포함된다.
블록은 다른 블록 아래 수직으로 배치되고 인라인은 수평으로 배치된다.
인라인 박스는 라인 또는 라인 박스 안쪽에 놓이며 라인은 적어도 가장 큰 박스만큼 크지만 baseline 정렬에서 더 커질 수 있다.
일반적인 흐름에 따라 위치를 결정한 만큼 필요한 만큼 이동
라인의 왼쪽 또는 오른쪽으로 이동
일반적인 흐름과 무관, 관여하지 않으며 면적은 상대적이다.
CSS의 z-index
속성에 의해 명시된다.
stacking contexts
으로 구분되며 뒤쪽 요소가 먼저 그려지고 앞쪽 요소는 사용자에게 가까운 쪽으로 나중에 그려진다. 앞쪽 요소는 겹치는 이전 요소를 가린다.
스택은 z-index
속성에 따라 순서를 결정하며 z-index
속성이 있는 박스는 지역 스택을 형성한다.
뷰포트는 바깥쪽의 스택이다.
How Browsers Work: Behind the scenes of modern web browsers
브라우저는 어떻게 동작하는가?
Understanding the Role of Rendering Engine in Browsers
Populating the page: how browsers work
조만간 책 나오면,, 싸인 부탁드릴게요!