상세 컨텐츠

본문 제목

브라우저는 어떻게 화면을 만들어 낼까? (feat: 브라우저 렌더링)

카테고리 없음

by maymj9798 2025. 1. 22. 22:45

본문

👉 파싱

  • 브라우저가 코드를 읽고 이해하는 과정

컴퓨터는 사람이 작성한 HTML, CSS, JS 코드를 이해하지 못한다
이를 컴퓨터가 이해할 수 있는 언어로 번역하는 과정이 파싱이다
번역과정을 통해 구조화된 데이터 - DOM, CSSOM으로 변환한다

💡 브라우저 렌더링?

  • "HTML, CSS, JS 코드를 브라우저가 읽어서 화면에 그리는 과정"
    즉, 코드를 화면에 그린다

👉 요청과 응답

브라우저는 필요한 리소스를 서버에 요청하고 응답을 받아 화면에 그려내는 역할을 한다

서버에 요청을 하기위해 브라우저의 주소창을 제공한다주소창을 제공한다

  1. 루트요청
  • Scheme + Host 만으로 구성된 요청
  • www.naver.com
  • 브라우저의 요청에 대해 서버는 정적파일 index.html 을 응답한다
  1. 다른 정적파일 요청
  • 루트 요청 뒤에 정적 파일의 경로를 적고 요청을 보내면 해당하는 정적파일을 응답한다
  • www.naver.com/cafe
  1. 응답에는 index.html 과 함께 css파일, js파일, 이미지, 폰트 등이 같이 포함되서 온다
  • html 파싱 중 link, script 태그를 만나면 html파싱을 중단하고 해당 파일을 서버로 요청하기 때문이다

👉 브라우저 렌더링 순서

🎈 1. HTML 파싱 + DOM 트리 생성

  • HTML파일을 위에서부터 순차적으로(동기적) 읽으며, DOM 트리를 만들기 시작
  • 서버의 응답인 HTML파일을 브라우저가 이해할 수 있는 자료구조(DOM)로 변환하는 과정
<html>
  <head></head>
  <body>
    <h1>Heading</h1>
  </body>
</html>

// 위 코드를 DOM으로 그림
├── html
│   ├── head
│   └── body
│       └── h1
           └── #text: "Heading"

🎈 2. CSS 파싱 + CSSOM 트리 생성

  • CSS 파일을 읽어서 새로운 CSS OBJECT MODEL 트리 구조를 만듬

  • 이 과정에서 HTML에 스타일을 적용시킴

  • HTML 파싱 중 link style태그를 만나면 DOM 생성을 중단하고, CSSOM 생성 시작

  • CSSOM 생성이 완료되면 다시 DOM 생성 재개

h1 {
    color: red,
    font-size: 20px,
}

// 위 코드를 CCSOM으로 그림
    Stylesheet
└── Rule
    ├── Selector: h1
    └── Declarations
        ├── Property: color
        │   └── Value: red
        ├── Property: font-size
        │   └── Value: 20px

🎈 3. DOM트리와 CSSOM트리를 합쳐서 렌더 트리를 생성

  • 화면에 그릴 요소와 스타일만으로 렌더트리를 만든다
    (제외되는 요소 : meta태그, script태그, display: none)

  • 완성된 DOM트리와 CSSOM트리는 렌더링을 위한 렌더트리로 결합됨

RenderRoot
└── RenderBlock (html)
    └── RenderBlock (body)
        └── RenderBlock (h1)
            ├── color: red
            ├── font-size: 20px
            └── text: "Heading"

🎈 4. 레이아웃 결정

  • 각 요소의 크기와 위치를 계산해서 화면 어디에 위치 시킬지 결정

🎈 5. 페인팅

  • 레이아웃을 바탕으로 픽셀단위로 화면에 그림 (플레이팅 단계)

🎈 6. 합성

  • 레이어 단위로 합쳐서 화면에 표시 (서빙 단계)

👉 자바스크립트 파싱과 실행

HTML 파싱과정 중 script 태그를 만나면
DOM 생성을 일시 중단하고 자바스크립트 코드 파싱을 위해 제어권을 자바스크립트 엔진에게 넘긴다
이후 자바스크립트 파싱과 실행이 완료되면
다시 제어권을 렌더링 엔진에게 넘겨 DOM 생성을 재개한다

HTML을 파싱한 결과인 DOM트리는 DOM API 를 제공한다
DOM API는 이미 생성된 DOM트리를 조작할수 있다 => document.getElementID

🎈 리플로우 + 리페인트

DOM API에 의해 DOM트리나 CSSOM트리가 변경되면
변경된 트리를 다시 결합하고
렌더링을 다시 한다

이때
레이아웃을 다시 계산하는게 리플로우
(HTML 요소의 크기, 위치, 너비, 높이 등이 변경되었을 때
-> 창크기 조절, css 속성 변경 - width, margin)

새로운 렌더트리를 페인트하는게 리페인트이다
(요소의 스타일만 변경
-> css 속성 변경 - color, bgColor)

리플로우의 비용은 크기 때문에 성능 최적화를 생각한다면 조심해야 하는 부분이다

🎈 AST

  1. 토크나이징
    자바스크립트 엔진은 단순 문자열인 자바스크립트 코드를 번역하여
    문법적 의미를 가지는 최소단위인 토큰들로 분해한다
  2. 파싱
    토큰들의 집합을 구문분석하여 AST - Absteact Syntax Tree를 생성한다
  3. 바이트 코드 생성과 실행
    생성된 AST는 인터프리터가 실행가능한 바이트코드로 변환되고 실행된다

🎯 script 태그의 위치

HTML을 파싱 할 때는
순차적으로 = 동기적으로 파싱되고 실행된다

그러면서 link태그를 만나면 CSSOM 트리를 생성하고
script태그를 만나면 js파일을 파싱하고 실행한다 (AST?)

이때
html이 파싱이 완료가 안된 상태에서
js코드 중 DOM을 조작하는 DOM API 코드가 있으면
문제가 발생한다

  1. HTML 태그 최하단
  • HTML을 전부 파싱 완료 한 다음에 script 태그를 만나면 JS를 다운받기 시작한다
  • JS다운이 완료되면 실행한다
  1. defer
  • HTML 파싱과 동시에 백그라운드에서 JS를 다운받는다 (비동기)
  • HTMl 파싱이 완료되면 다운 받아놓은 JS를 순차적으로 실행한다
<script defer src="파일1">
<script defer src="파일2">

// html 파싱 완료 => 파일1 실행 => 파일2 실행
  1. async
  • HTML 파싱과 동시에 백그라운드에서 JS를 다운받는다 (비동기)
  • JS 다운이 완료 되면 완료되는 순으로 HTML 파싱을 중단되고 JS파일을 실행한다
  • 이후 HTMl 파싱을 다시 시작한다
<script async src="파일1">
<script async src="파일2">

// html 파싱 중 => 완료된 순으로 파일 실행