IT/Front-End

브라우저는 어떻게 동작하는가?

라임웨일 2022. 1. 20. 10:46
반응형

 

 

이 글은 이스라엘 개발자 탈리 가르시엘(Tali Garsiel)이 html5rocks.com에 게시한 "How Browsers WorkBehind the scenes of modern web browsers"를 번역한 글입니다. 탈리 가르시엘은 몇 년간 브라우저 내부와 관련된 공개 자료를 확인하고, C++ 코드 수백만 줄 분량의 WebKit이나 Gecko 같은 오픈소스 렌더링 엔진의 소스 코드를 직접 분석하면서 어떻게 브라우저가 동작하는지 파악했습니다. 

 

📖 소개

브라우저는 아마도 가장 많이 사용하는 소프트웨어입니다. 이 글을 통해 브라우저가 어떻게 동작하는지 이해하고 설명하려고 합니다. 이 글을 읽고 나면, 브라우저 주소 창에 특정 URL을 입력했을 때 어떤 과정을 거쳐 페이지가 화면에 보이게 되는지 이해하게 될 것입니다.

✔ 이 글에서 설명하는 브라우저

최근에는 인터넷 익스플로러(Edge 포함), 파이어폭스, 사파리, 크롬, 오페라 다섯 개의 브라우저를 많이 사용하지만 이 글에서는 파이어폭스, 크롬, 사파리와 같은 오픈소스 브라우저를 예로 들 것입니다. 참고로 사파리는 부분적으로 오픈소스입니다. StatCounter 브라우저 통계에 의하면 2022년 1월 기준으로 현재 크롬이 63.8%, 사파리 19.6%의 점유유를 보이고 Edge는 3.99%, 파이어폭스 3.91%의 점유율로 사실상 크롬이 대부분의 브라우저  점유율을 차지합니다. 

 

💡 브라우저의 주요 기능

브라우저의 주요 기능은 사용자가 선택한 자원을 서버에 요청하고 브라우저에 표시하는 것입니다. 자원은 보통 HTML 문서지만 PDF나 이미지 또는 다른 형태일 수 있습니다. 자원의 주소는 URI(Uniform Resource Identifier)에 의해 정해집니다.

브라우저는 HTML과 CSS 명세에 따라 HTML 파일을 해석해서 표시하는데 이 명세는 웹 표준화 기구인 W3C(World Wide Web Consortium)에서 정합니다. 과거에는 브라우저들이 일부만 이 명세에 따라 구현하고 독자적인 방법으로 확장함으로써 웹 제작자가 심각한 호환성 문제를 겪었지만 최근에는 대부분의 브라우저가 표준 명세를 따르고 있습니다.

브라우저의 사용자 인터페이스는 서로 닮아 있는데 다음과 같은 요소들이 일반적입니다.

  • URI를 입력할 수 있는 주소 표시 줄
  • 이전 버튼과 다음 버튼
  • 북마크
  • 새로 고침 버튼과 현재 문서의 로드를 중단할 수 있는 정지 버튼
  • 홈 버튼

브라우저의 사용자 인터페이스는 표준 명세가 없음에도 불구하고 수년간 서로의 장점을 모방하면서 현재에 이르게 되었습니다. HTML5 명세는 주소 표시줄, 상태 표시줄, 도구 모음과 같은 일반적인 요소를 제외하고 브라우저의 필수 UI를 정의하지 않았습니다. 물론 파이어폭스의 다운로드 관리자와 같이 브라우저에 특화된 기능도 있습니다.

💡 브라우저의 기본 구조

브라우저의 주요 구성 요소는 다음과 같습니다.(1.1)

  1. 사용자 인터페이스 - 주소 표시줄, 이전/다음 버튼, 북마크 메뉴 등. 요청한 페이지를 보여주는 창을 제외한 나머지 모든 부분.
  2. 브라우저 엔진 - 사용자 인터페이스와 렌더링 엔진 사이의 동작을 제어.
  3. 렌더링 엔진 - 요청한 콘텐츠를 표시. 예를 들어 HTML을 요청하면 HTML과 CSS를 파싱 하여 화면에 표시.
  4. 통신 - HTTP 요청과 같은 네트워크 호출에 사용됨. 이것은 플랫폼 독립적인 인터페이스이고 각 플랫폼 하부에서 실행됨.
  5. UI 백엔드 - 콤보 박스와 창 같은 기본적인 장치를 그림. 플랫폼에서 명시하지 않은 일반적인 인터페이스로서, OS 사용자 인터페이스 체계를 사용.
  6. 자바스크립트 해석기 - 자바스크립트 코드를 해석하고 실행.
  7. 자료 저장소 - 이 부분은 자료를 저장하는 계층으로 쿠키를 저장하는 것과 같이 모든 종류의 자원을 하드 디스크에 저장할 필요가 있고 HTML5 명세에는 브라우저가 지원하는 ' 데이터 베이스'가 정의되어 있음.

 

브라우저의 주요 구성 요소

크롬은 대부분의 브라우저와 달리 각 탭마다 별도의 렌더링 엔진 인스턴스를 유지하는 것이 주목할 부분이며 각 탭은 독립된 프로세스로 처리됩니다.

📖 렌더링 엔진

렌더링 엔진의 역할은 요청받은 내용을 브라우저 화면에 표시하는 일로서 렌더링 엔진은 HTML 및 XML 문서와 이미지를 표시할 수 있습니다. 물론 플러그인이나 브라우저 확장 기능을 이용해 PDF와 같은 다른 유형도 표시할 수 있습니다. 그러나 이 장에서는 HTML과 이미지를 CSS로 표시하는 주된 사용 패턴에 초점을 맞출 예정입니다.

✔ 렌더링 엔진들

이 글에서 다루는 브라우저인 파이어폭스와 크롬, 사파리는 두 종류의 렌더링 엔진으로 제작되었다. 파이어폭스는 모질라에서 직접 만든 게코(Gecko) 엔진을 사용하고 사파리와 크롬은 웹킷(Webkit) 엔진을 사용합니다.

웹킷은 최초 리눅스 플랫폼에서 동작하기 위해 제작된 오픈소스 엔진인데 애플이 맥과 윈도우즈에서 사파리 브라우저를 지원하기 위해 수정을 하였습니다. 더 자세한 내용은 webkit.org를 참조합니다.

✔ 동작 과정

렌더링 엔진은 통신으로부터 요청한 문서의 내용을 얻는 것으로 시작하는데 문서의 내용은 보통 8KB 단위로 전송됩니다.

다음은 렌더링 엔진의 기본적인 동작 과정입니다.

렌더링 엔진의 동작 과정

 

  1. 렌더링 엔진은 HTML 문서를 파싱 하고 "콘텐츠 트리" 내부에서 태그를 DOM 노드로 변환합니다.
  2. 그 다음 외부 CSS 파일과 함께 포함된 스타일 요소도 파싱합니다. 스타일 정보와 HTML 표시 규칙은 "렌더 트리"라고 부르는 또 다른 트리를 생성합니다. 렌더 트리는 색상 또는 면적과 같은 시각적 속성이 있는 사각형을 포함하고 있는데 정해진 순서대로 화면에 표시됩니다.
  3. 렌더 트리 생성이 끝나면 배치가 시작되는데 이것은 각 노드가 화면의 정확한 위치에 표시되는 것을 의미합니다.
  4. 다음은 UI 백엔드에서 렌더 트리의 각 노드를 가로지르며 형상을 만들어 내는 그리기 과정입니다.일련의 과정들이 점진적으로 진행된다는 것을 아는 것이 중요합니다.
  5. 렌더링 엔진은 좀 더 나은 사용자 경험을 위해 가능하면 빠르게 내용을 표시하는데 모든 HTML을 파싱 할 때까지 기다리지 않고 배치와 그리기 과정을 시작합니다. 네트워크로부터 나머지 내용이 전송되기를 기다리는 동시에 받은 내용의 일부를 먼저 화면에 표시합니다.

✔ 동작 과정 예

웹킷 동작 과정

 

모질라의 게코 렌더링 엔진 동작 과정(3.6)

 

웹킷과 게코가 용어를 약간 다르게 사용하고 있지만 동작 과정은 기본적으로 동일하다는 것을 그림 3과 그림 4에서 알 수 있습니다.

게코는 시각적으로 처리되는 렌더 트리를 "형상 트리(frame tree)"라고 부르고 각 요소를 형상(frame)이라고 하는데 웹킷은 "렌더 객체(render object)"로 구성되어 있는 "렌더 트리(render tree)"라는 용어를 사용합니다.

웹킷은 요소를 배치하는데 "배치(layout)"라는 용어를 사용하지만 게코는 "리플로(reflow)"라고 부릅니다. "어태치먼트(attachment)"는 웹킷이 렌더 트리를 생성하기 위해 DOM 노드와 시각 정보를 연결하는 과정입니다.

게코는 HTML과 DOM 트리 사이에 "콘텐츠 싱크(content sink)"라고 부르는 과정을 두는데 이는 DOM 요소를 생성하는 공정으로 웹킷과 비교하여 의미 있는 차이점이라고 보지는 않습니다.

 

📖 파싱과 DOM 트리 구축

👉 파싱 일반

파싱은 렌더링 엔진에서 매우 중요한 과정이기 때문에 더 자세히 다룰 필요가 있습니다. 

문서 파싱은 브라우저가 코드를 이해하고 사용할 수 있는 구조로 변환하는 것을 의미합니다. 파싱 결과는 보통 문서 구조를 나타내는 노드 트리인데 파싱 트리(parse tree) 또는 문법 트리(syntax tree)라고 부릅니다.

예를 들면 2+3-1과 같은 표현식은 다음과 같은 트리가 됩니다.

수학 표현식을 파싱한 트리 노드

 

✔ 문법

파싱은 문서에 작성된 언어 또는 형식의 규칙에 따르는데 파싱 할 수 있는 모든 형식은 정해진 용어와 구문 규칙에 따라야 하는데 이것을 문맥 자유 문법이라고 합니다. 인간의 언어는 이런 모습과는 다르기 때문에 기계적으로 파싱이 불가능합니다.

✔ 파서-어휘 분석기 조합

파싱은 어휘 분석과 구문 분석이라는 두 가지로 구분할 수 있습니다.

어휘 분석은 자료를 토큰으로 분해하는 과정으로서 토큰은 유효하게 구성된 단위의 집합체로 용어집이라고도 할 수 있는데 인간의 언어로 말하자면 사전에 등장하는 모든 단어에 해당됩니다.

 

구문 분석은 언어의 구문 규칙을 적용하는 과정입니다.

파서는 보통 두 가지 일을 하는데 자료를 유효한 토큰으로 분해하는 어휘 분석기(토큰 변환기라고도 부름)가 있고 언어 구문 규칙에 따라 문서 구조를 분석함으로써 파싱 트리를 생성하는 파서가 있습니다. 어휘 분석기는 공백과 줄 바꿈 같은 의미 없는 문자를 제거합니다.

소스로부터 파싱 트리를 만드는 과정

 

파싱 과정은 반복되며 파서는 보통 어휘 분석기로부터 새 토큰을 받아서 구문 규칙과 일치하는지 확인합니다. 규칙에 맞으면 토큰에 해당하는 노드가 파싱 트리에 추가되고 파서는 또 다른 토큰을 요청합니다.

규칙에 맞지 않으면 파서는 토큰을 내부적으로 저장하고 토큰과 일치하는 규칙이 발견될 때까지 요청합니다. 맞는 규칙이 없는 경우 예외로 처리하는데 이것은 문서가 유효하지 않고 구문 오류를 포함하고 있다는 의미입니다.

 

✔ 변환

파서 트리는 최종 결과물이 아닙니다. 파싱은 보통 문서를 다른 양식으로 변환하는데 컴파일이 하나의 예가 됩니다. 소스 코드를 기계 코드로 만드는 컴파일러는 파싱 트리 생성 후 이를 기계 코드 문서로 변환합니다.

컴파일 과정

 

✔ 파서의 종류

파서는 기본적으로 하향식 파서와 상향식 파서가 있습니다. 하향식 파서는 구문의 상위 구조로부터 일치하는 부분을 찾기 시작하는데 반해 상향식 파서는 낮은 수준에서 점차 높은 수준으로 찾습니다.

 

👉 HTML 파서

HTML 파서는 HTML 마크업을 파싱 트리로 변환합니다.

 

✔ DOM

"파싱 트리"는 DOM 요소와 속성 노드의 트리로서 출력 트리가 됩니다. DOM은 문서 객체 모델(Document Object Model)의 준말로서  HTML 문서의 객체 표현이고 외부를 향하는 자바스크립트와 같은 HTML 요소의 연결 지점입니다. 트리의 최상위 객체는 문서입니다. DOM은 마크업과 1:1의 관계를 맺습니다.

 <html>
  <body>
   <p>Hello World</p>
   <div><img src="example.png" /></div>
  </body>
</html>  

이것은 아래와 같은 DOM 트리로 변환할 수 있습니다.

예제 마크업의 DOM 트리

 

HTML과 마찬가지로 DOM은 W3C에 의해 명세(www.w3.org/DOM/DOMTR)가 정해져 있습니다. 이것은 문서를 다루기 위한 일반적인 명세인데 부분적으로 HTML 요소를 설명하기도 합니다. 

트리가 DOM 노드를 포함한다고 말하는 것은 DOM 접점의 하나를 실행하는 요소를 구성한다는 의미로서 브라우저는 내부의 다른 속성들을 이용하여 이를 구체적으로 실행합니다.

 

✔  파싱 알고리즘

앞서 말한 대로 HTML은 일반적인 하향식 또는 상향식 파서로 파싱이 되지 않는데 그 이유는 다음과 같습니다.

  1. 언어의 너그러운 속성.
  2. 잘 알려져 있는 HTML 오류에 대한 브라우저의 관용.
  3. 변경에 의한 재 파싱. 일반적으로 소스는 파싱 하는 동안 변하지 않지만 HTML에서 document.write을 포함하고 있는 스크립트 태그는 토큰을 추가할 수 있기 때문에 실제로는 입력 과정에서 파싱이 수정됨.

 

일반적인 파싱 기술을 사용할 수 없기 때문에 브라우저는 HTML 파싱을 위해 별도의 파서를 생성합니다. 파싱 알고리즘은 HTML 자세히 설명되어 있습니다. 알고리즘은 토큰화와 트리 구축 이렇게 두 단계로 되어 있습니다.  토큰화는 어휘 분석으로서 입력 값을 토큰으로 파싱합니다. HTML에서 토큰은 시작 태그, 종료 태그, 속성 이름과 속성 값입니다. 토큰화는 토큰을 인지해서 트리 생성자로 넘기고 다름 토큰을 확인하기 위해 다음 문자를 확인합니다. 입력의 마지막까지 이 과정을 반복합니다.

HTML 파싱 과정(HTML5 명세에서 가져옴)

✔ 토큰화 알고리즘

알고리즘의 결과물은 HTML 토큰으로 알고리즘은 상태 기계(State Machine)라고 볼 수 있습니다.  각 상태는 하나 이상의 연속된 문자를 입력받아 이 문자에 따라 상태를 갱신하는데 결과는 현재의 토큰화 상태와 트리 구축 상태의 영향을 받습니다. 이것은 같은 문자를 읽어 들여도 현재 상태에 따라 다음 상태의 결과가 다르게 나온다는 것을 의미합니다. 

다음은 HTML 토큰화를 설명하기 위한 기본적인 예제입니다.

 <html>
   <body>
      Hello world
   </body>
</html>  

 

초기 상태는 "자료 상태"입니다. <(왼쪽 꺽쇠) 문자를 만나면 상태는 "태그 열림 상태"로 변하고 a부터 z까지의 문자를 만나면서 "시작 태그 토큰"을 생성하고 상태는 "태그 이름 상태"로 변하는데 이 상태는 >(오른쪽 꺽쇠) 문자를 만날 때까지 유지하게 됩니다.

각 문자에는 새로운 토큰 이름이 붙는데 이 경우 생성된 토큰은 html 토큰입니다.

>(오른쪽 꺽쇠) 문자에 도달하면 현재 토큰이 발행되고 상태는 다시 "자료 상태"로 바뀌게 됩니다. 태그는 동일한 절차에 따라 처리됩니다.

 

위의 예제를 보게 되면 지금까지 html 태그와 body 태그를 발행했고 다시 "자료 상태"로 돌아왔습니다.  Hello World의 H 문자를 만나면 문자 토큰이 생성되고 발행될 것입니다. 이것은 종료 태그의 <(왼쪽 꺽쇠) 문자를 만날 때까지 진행되며 Hello World의 각 문자를 위한 문자 토큰을 발행합니다

 

다시 "태그 열림 상태"가 되면 /(슬래쉬) 문자는 종료 태그 토큰을 생성하고 "태그 이름 상태"로 변경됩니다. 이 상태는 >(오른쪽 꺽쇠) 문자를 만날 때까지 유지되며 새로운 태그 토큰이 발행되고 다시 "자료 상태"가 되고 동일하게 처리됩니다.

입력 예제의 토큰화

 

✔ 트리 구축 알고리즘

파서가 생성되면 문서 객체가 생성되며 트리 구축이 진행되는 동안 문서 최상단에서는 DOM 트리가 수정되고 요소가 추가됩니다. 토큰화에 의해 발행된 각 노드는 트리 생성자에 의해 처리되고 각 토큰을 위한 DOM 요소의 명세는 정의되어 있습니다. DOM 트리에 요소를 추가하는 것이 아니라면 열린 요소는 스택(임시 버퍼 저장소)에 추가됩니다.  이 스택은 부정확한 중첩과 종료되지 않은 태그를 교정합니다. 알고리즘은 상태 기계라고 설명할 수 있고 상태는 "삽입 모드"라고 부릅니다.

 

- 입력 예제의 트리 생성 과정

 <html>
   <body>
      Hello world
   </body>
</html>  

예제 html 트리 구축

 

✔ 파싱이 끝난 이후의 동작

브라우저는 문서와 상호작용할 수 있게 되고 문서 파싱 이후에 실행되어야 하는 "지연" 모드 스크립트를 파싱 하기 시작합니다. 문서 상태는 "완료"가 되고 "로드" 이벤트가 발생합니다. 보다 자세한 내용은 HTML5 토큰화 알고리즘과 트리 구축에서 볼 수 있습니다.

 

✔ 브라우저의 오류 처리

HTML 페이지에서 "유효하지 않은 구문"이라는 오류는 볼 수 없습니다. 이는 브라우저가 모든 오류 구문을 교정하기 때문입니다.

아래 오류가 포함된 HTML 예제를 통해 좀 더 자세히 살펴보겠습니다.

<html>  
   <mytag></mytag>
   <div>
     <p>
   </div>
   Really lousy HTML
   </p>
</html>  

"mytag"는 표준 태그가 아니고 "p" 태그와 "div" 태그는 중첩 오류가 있지만 브라우저는 화면을 올바르게 표시하는데 이는 파서가 HTML 제작자의 실수를 수정했기 때문입니다. 규칙에 맞게 잘 작성된 문서라면 파싱이 수월하겠지만 불행하게도 형식에 맞지 않게 작성된 많은 HTML 문서를 다뤄야 하기 때문에 파서는 오류에 대비하여 자체적으로 오류를 수정합니다.

 

파서는 다음과 같은 오류를 처리합니다.

  1. 어떤 태그의 안쪽에 추가하려는 태그가 금지된 것일 때 일단 허용된 태그를 먼저 닫고 금지된 태그는 외부에 추가
  2. 파서가 직접 요소를 추가해서는 안됨. 문서 제작자에 의해 뒤늦게 요소가 추가될 수 있고 생략 가능한 경우도 있음. HTML, HEAD, BODY, TBODY, TR, TD, LI 태그가 이런 경우에 해당
  3. 인라인 요소 안쪽에 블록 요소가 있는 경우 부모 블록 요소를 만날 때까지 모든 인라인 태그를 닫음
  4. 이런 방법이 도움이 되지 않으면 태그를 추가하거나 무시할 수 있는 상태가 될 때까지 요소를 닫음

 

👉 CSS 파싱

HTML과는 다르게 CSS는 문맥 자유 문법이고 소개 글에서 설명했던 파서 유형을 이용하여 파싱이 가능합니다. 실제로 CSS 명세는 CSS 어휘와 문법을 정의하고 있습니다.

 

CSS 파싱

 

👉 스크립트와 스타일 시트의 진행 순서

✔ 스크립트

웹은 파싱과 실행이 동시에 수행되는 동기화(synchronous) 모델입니다. 일반적으로 파서가 < script > 태그를 만나면 즉시 파싱 하고 실행하기를 기대하는데 스크립트가 실행되는 동안 문서의 파싱은 중단됩니다. 스크립트가 외부에 있는 경우 우선 네트워크로부터 자원을 가져와야 하는데 이 또한 실시간으로 처리되고 자원을 받을 때까지 파싱은 중단됩니다. 

HTML5는 스크립트를 비동기(asynchronous)로 처리하는 속성을 추가했기 때문에 별도의 맥락에 의해 파싱 되고 실행됩니다.

✔ 예측 파싱

웹킷과 파이어폭스는 예측 파싱과 같은 최적화를 지원합니다. 스크립트를 실행하는 동안 다른 스레드는 네트워크로부터 다른 자원을 찾아 내려받고 문서의 나머지 부분을 파싱합니다. 이런 방법은 자원을 병렬로 연결하여 받을 수 있고 전체적인 속도를 개선합니다. 참고로 예측 파서는 DOM 트리를 수정하지 않고 메인 파서의 일로 넘기게 됩니다. 예측 파서는 외부 스크립트, 외부 스타일 시트와 외부 이미지와 같이 참조된 외부 자원을 파싱합니다.

✔ 스타일 시트

한편 스타일 시트는 다른 모델을 사용한다. 이론적으로 스타일 시트는 DOM 트리를 변경하지 않기 때문에 문서 파싱을 기다리거나 중단할 이유가 없습니다. 그러나 스크립트가 문서를 파싱하는 동안 스타일 정보를 요청하는 경우라면 문제가 됩니다. 스타일이 파싱 되지 않은 상태라면 스크립트는 잘못된 결과를 내놓기 때문에 많은 문제를 야기하며 이런 문제는 흔치 않은 것처럼 보이지만 매우 빈번하게 발생합니다. 파이어폭스는 아직 로드 중이거나 파싱 중인 스타일 시트가 있는 경우 모든 스크립트의 실행을 중단합니다. 한편 웹킷은 로드되지 않은 스타일 시트 가운데 문제가 될만한 속성이 있을 때에만 스크립트를 중단합니다.

 

📖 렌더 트리 구축

DOM 트리가 구축되는 동안 브라우저는 렌더 트리를 구축합니다. 표시해야 할 순서와 문서의 시각적인 구성 요소로써 올바른 순서로 내용을 그려낼 수 있도록 하기 위한 목적이 있습니다.

파이어폭스는 이 구성 요소를 "형상(frames)"이라고 부르고 웹킷은 "렌더러(renderer)" 또는 "렌더 객체(render object)"라는 용어를 사용합니다. 렌더러는 자신과 자식 요소를 어떻게 배치하고 그려내야 하는지 알고 있습니다.

각 렌더러는 CSS2 명세에 따라 노드의 CSS 박스에 부합하는 사각형을 표시하며 렌더러는 너비, 높이 그리고 위치와 같은 기하학적 정보를 포함합니다.

박스 유형은 노드와 관련된 "display" 스타일 속성의 영향을 받습니다. 요소 유형 또한 고려해야 하는데 예를 들면 폼 컨트롤과 표는 특별한 구조입니다. 요소가 특별한 렌더러를 만들어야 한다면 웹킷은 creatRenderer 메서드를 무시하고 비기하학 정보를 포함하는 스타일 객체를 표시합니다.

 

👉 DOM 트리와 렌더 트리의 관계

렌더러는 DOM 요소에 부합하지만 1:1로 대응하는 관계는 아닙니다. 예를 들어 "head" 요소와 같은 비시각적 DOM 요소는 렌더 트리에 추가되지 않습니다. 또한 display 속성에 "none" 값이 할당된 요소는 트리에 나타나지 않습니다(visibility 속성에 "hidden" 값이 할당된 요소는 트리에 나타납니다).

CSS 명세에 의하면 인라인 박스는 블록 박스만 포함하거나 인라인 박스만을 포함해야 하는데 인라인과 블록 박스가 섞인 경우 인라인 박스를 감싸기 위한 익명의 블록 렌더러가 생성됩니다. 어떤 렌더 객체는 DOM 노드에 대응하지만 트리의 동일한 위치에 있지 않습니다. float 처리된 요소 또는 position 속성 값이 absolute로 처리된 요소는 흐름에서 벗어나 트리의 다른 곳에 배치된 상태로 형상이 그려집니다. 대신 자리 표시자가 원래 있어야 할 곳에 배치됩니다.

 

렌더 트리와 DOM 트리 대응(3.1). "뷰포트"는 최초의 블록이다. 웹킷에서는 "RenderView" 객체가 이 역할을 한다.

👉 트리를 구축하는 과정

파이어폭스에서 프레젠테이션은 DOM 업데이트를 위한 리스너로 등록됩니다. 프레젠테이션은 형상 만들기를 FrameConstructor에 위임하고 FrameConstructor는 스타일(스타일 계산 참고)을 결정하고 형상을 만듭니다.

웹킷에서는 스타일을 결정하고 렌더러를 만드는 과정을 "어태치먼트(attachment)"라고 부르며 모든 DOM 노드에는 "attach" 메서드가 있습니다. 어태치먼트는 동기적인데 DOM 트리에 노드를 추가하면 새 노드의 "attach" 메서드를 호출합니다. (CSS처리 모델 명세를 참고)

 

📖 스타일 계산

렌더 트리를 구축하려면 각 렌더 객체의 시각적 속성에 대한 계산이 필요한데 이것은 각 요소의 스타일 속성을 계산함으로써 처리됩니다. 스타일은 인라인 스타일 요소와 HTML의 시각적 속성(예를 들면 bgcolor 같은 HTML 속성)과 같은 다양한 형태의 스타일 시트를 포함하는데 HTML의 시각적 속성들은 대응하는 CSS 스타일 속성으로 변환됩니다. 최초의 스타일 시트는 브라우저가 제공하는 기본 스타일 시트인데 페이지 제작자 또는 사용자도 이를 제공할 수 있습니다. 

👉 파이어폭스 규칙 트리

파이어폭스는 스타일 계산을 쉽게 처리하기 위해 규칙 트리와 스타일 문맥 트리라고 하는 두 개의 트리를 더 가지고 있습니다. 웹킷도 스타일 객체를 가지고 있지만 스타일 문맥 트리처럼 저장되지 않고 오직 DOM 노드로 관련 스타일을 처리합니다.

 

파이어폭스 스타일 문맥 트리(2.2)

스타일 문맥에는 최종 값이 저장되어 있고 값은 올바른 순서 안에서 부합하는 규칙을 적용하고 논리로부터 구체적인 값으로 변환함으로써 계산됩니다. 예를 들어 논리적인 값이 화면의 백분율(%)이라면 이 값은 계산에 의해 절대적인 단위(px)로 변환됩니다. 

부합하는 모든 규칙은 트리에 저장하는데 경로의 하위 노드가 높은 우선순위를 갖고 규칙 저장은 느리게 처리됩니다. 트리는 처음부터 모든 노드를 계산하지 않지만 노드 스타일이 계산될 필요가 있을 때 계산된 경로를 트리에 추가합니다.

 

✔ 쉬운 선택을 위한 규칙 다루기

- CSS 규칙을 외부 스타일 시트에서 선언하거나 style 요소에서 선언

p {color:blue}  

 

- 인라인 스타일 속성

<p style="color:blue"></p>  

- HTML의 시각적 속성(이것들은 CSS 규칙으로 변환됨)

<p bgcolor="blue"></p>  

 

마지막 두 가지 스타일은 자신이 스타일 속성을 가지고 있거나 HTML 속성을 이용하여 연결할 수 있기 때문에 요소에 쉽게 연결됩니다. 스타일 시트를 파싱한 후 규칙은 선택자에 따라 여러 해시맵 중 하나에 추가됩니다.

아이디, 클래스 이름, 태그 이름을 사용한 맵이 있고 이런 분류에 맞지 않는 것을 위한 일반적인 맵이 있는데 선택자가 아이디인 경우 규칙은 아이디 맵에 추가되고 선택자가 클래스인 경우 규칙은 클래스 맵에 추가됩니다.

 

✔ 상속 순서에 따라 규칙 적용하기

스타일 객체는 모든 CSS 속성을 포함하고 있는데 어떤 규칙과도 일치하지 않는 일부 속성은 부모 요소의 스타일 객체로부터 상속받고 그 외 다른 속성들은 기본 값으로 설정됩니다. 문제는 하나 이상의 속성이 정의될 때 시작되고 다단계 순서가 이 문제를 해결하게 됩니다.

 

✔ 스타일 시트 다단계 순서(스타일 시트 점수 계산)

스타일 속성 선언은 여러 스타일 시트에서 나타날 수 있고 하나의 스타일 시트 안에서도 여러 번 나타날 수 있는데 이것은 규칙을 적용하는 순서가 매우 중요하다는 것을 의미합니다. 이것을 "상속(cascade)" 순서라고 하며 CSS2 명세에 따르면 상속 순서는 다음과 같습니다(우선 순위가 낮은 것에서 높은 순서임).

  1. 브라우저 선언 (browser declarations)
  2. 사용자 일반 선언 (user normal declarations)
  3. 저작자 일반 선언 (author normal declarations)
  4. 저작자 중요 선언 (author important declarations)
  5. 사용자 중요 선언 (user important declarations)

 

👉 CSS 박스 모델

CSS 박스 모델은 문서 트리에 있는 요소를 위해 생성되고 시각적 서식 모델에 따라 배치된 사각형 박스를 설명합니다.

각 박스는 콘텐츠 영역(문자, 이미지 등)과 선택적인 패딩과 테두리, 여백이 있습니다.

CSS 박스 모델

각 노드는 이런 상자를 0에서 n개 생성하며 모든 요소는 만들어질 박스의 유형을 결정하는 "display" 속성을 갖는데 이 속성의 유형은 다음과 같습니다.

  • block  - 블록 상자를 만든다.
  • inline - 하나 또는 그 이상의 인라인 상자를 만든다.
  • none - 박스를 만들지 않는다.

 

👉 위치 결정 방법

✔ 위치를 결정하는 방법은 다음과 같은 세 가지 입니다.

  1. Normal - 객체는 문서 안의 자리에 따라 위치가 결정됨. 이것은 렌더 트리에서 객체의 자리가 DOM 트리의 자리와 같고 박스 유형과 면적에 따라 배치됨을 의미
  2. Float - 객체는 우선 일반적인 흐름에 따라 배치된 다음 왼쪽이나 오른쪽으로 흘러 이동.
  3. Absolute - 객체는 DOM 트리 자리와는 다른 렌더 트리에 놓임

 

✔ 위치는 "position" 속성과 "float" 속성에 의해 결정됩니다.

  • static과 relative로 설정하면 일반적인 흐름에 따라 위치가 결정.
  • absolute와 fixed로 설정하면 절대적인 위치가 됨.

position 속성을 정의하지 않으면 static이 기본 값이 되며 일반적인 흐름에 따라 위치가 결정됩니다. static 아닌 다른 속성 값(relatice, absolute, fixed)을 사용하면 top, bottom, left, right 속성으로 위치를 결정할 수 있습니다.

 

✔ 박스가 배치되는 방법은 다음과 같은 방법으로 결정됩니다.

  • 박스 유형(display, inline ...)
  • 박스 크기(width, height ...)
  • 위치 결정 방법(position, float)
  • 추가적인 정보 - 이미지 크기와 화면 크기 등

 

👉 박스 유형

- 블록 박스: 브라우저 창에서 사각형 블록을 형성합니다.

블록 박스

 

- 인라인 박스: 블록이 되지 않고 블록 내부에 포함됩니다.

인라인 박스

 

- 블록은 다른 블록 아래 수직으로 배치되고 인라인은 수평으로 배치됩니다.

블록과 인라인 배치

 

인라인 박스는 라인 또는 "라인 박스" 안쪽에 놓이게 됩니다. 라인은 적어도 가장 큰 박스만큼 크지만 "baseline" 정렬일 때 더 커질 수 있습니다. 이것은 요소의 하단이 다른 상자의 하단이 아닌 곳에 배치된 경우를 의미합니다. 포함하는 너비가 충분하지 않으면 인라인은 몇 줄의 라인으로 배치되는데 이것은 보통 문단 안에서 발생합니다.

라인

📖 위치 잡기

👉상대적인 위치

- 상대적인 위치 잡기는 일반적인 흐름에 따라 위치를 결정한 다음 필요한 만큼 이동합니다.

상대적인 위치 잡기

 

✔ 플로트(Float)

- 플로트 박스는 라인의 왼쪽 또는 오른쪽으로 이동합니다. 흥미로운 점은 다른 박스가 이 주변을 흐른다는 것입니다.

 

<p>  
<img src="http://helloworld.naver.com/image.gif" alt="image.gif" width="100" height="100" style="float:right">  
Lorem ipsum dolor sit amet, consectetuer...  
</p>  

플로트(float)

✔ 절대적인(absolute) 위치와 고정된(fixed) 위치

- 절대와 고정 배치는 일반적인 흐름과 무관하게 결정되고, 일반적인 흐름에 관여하지 않으며, 면적은 부모에 따라 상대적입니다. 고정인 경우 뷰포트로부터 위치를 결정합니다.

고정된 위치 잡기

⚠️ 고정된 박스는 문서가 스크롤되어도 따라 움직이지 않습니다.

 

✔ 층 표현

이것은 CSS의 z-index 속성에 의해 명시됩니다. 층은 박스의 3차원 표현이고 "z 축"을 따라 위치를 정하게 됩니다.

박스는 (stacking contexts라고 부르는) 스택으로 구분됩니다. 각 스택에서 뒤쪽 요소가 먼저 그려지고 앞쪽 요소는 사용자에게 가까운 쪽으로 나중에 그려집니다. 가장 앞쪽에 위치한 요소는 겹치는 이전 요소를 가리게 됩니다.

스택은 z-index 속성에 따라 순서를 결정하며 z-index 속성이 있는 박스는 지역 스택(local stack)을 형성합니다. 뷰포트는 바깥쪽의 스택(outer stack)입니다.

<style type="text/css">  
div {  
    position: absolute;
    left: 2in;
    top: 2in;
}
</style>  
<p>  
    <div style="z-index:3;background-color:red;width:1in;height:1in"></div>
    <div style="z-index:1;background-color:green;width:2in;height:2in"></div>
</p>  

&nbsp;고정 위치 잡기

붉은색 박스가 초록색 박스보다 마크업에서 먼저 나오기 때문에 일반적인 흐름이라면 먼저 그려져야 하지만 z-index 속성이 높기 때문에 더 앞쪽에 표시됩니다.

 

 


 

위에 글은 브라우저가 어떻게 동작하는지에 대한 글이 주제인 내용이기 때문에 제가 판단하여 전체적인 문맥 상 너무 자세한 내용이나 이해가 힘든 부분은 글을 좀 더 읽기 쉽게 첨삭하였습니다.

일부 내용은 최신 데이터로 수정을 하였습니다.

 

첨삭되지 않은 모든 내용을 확인 하고 싶으신 분들은 아래 기재 된  출처에서 글을 확인하시면 됩니다.

감사합니다.

 

출처 : https://d2.naver.com/helloworld/59361

 

 

반응형
광고차단(애드블록)프로그램이나 브라우저를 사용중이시면 프로그램을 비활성화이나 블로그 주소를 예외 처리 해주시면 광고가 노출됩니다. 귀찮고 번거롭겠지만 광고 클릭은 저에게는 큰 힘이 됩니다. 🙇🏻‍♂️🙇🏻‍♀️
제 블로그의 모든 글은 제가 직접 작성 하고 다른 글을 참고할 때는 이전 글보다 읽기 편하게 수정해서 작성하고 있습니다. 커피 한잔 사먹고 더 열심히 좋은글로 보답하겠습니다.
오늘도 제 블로그에 와 주셔서 감사합니다. :)
//