Skip to content

브라우저 동작 원리 ​

브라우저는 사용자가 요청한 자원(HTML, CSS, 이미지 등)을 서버에서 받아 와서, 정해진 규칙에 따라 해석한 뒤 화면에 그려 주는 프로그램입니다. 주소창에 https://naver.com을 입력하고 Enter를 누른 순간부터 화면이 보이기까지, 브라우저 안에서는 "받아 오기 → 해석하기 → 그리기" 과정이 쉬지 않고 이어집니다.

한눈에 보기 ​

  • 브라우저가 하는 일은 크게 두 가지입니다.
    1. 네트워크: 서버를 찾아가서 문서와 파일을 받아 옵니다.
    2. 렌더링(Rendering): 받아 온 HTML과 CSS를 해석해서 눈에 보이는 화면으로 바꿉니다.
  • 비유: 브라우저는 설계도를 받아 집을 짓는 건설 회사와 같습니다.
    • HTML은 "방이 몇 개고 어디에 무엇이 있는지" 적힌 구조 설계도입니다.
    • CSS는 "벽지는 무슨 색, 창문은 얼마나 크게" 적힌 인테리어 지시서입니다.
    • 렌더링 엔진은 두 문서를 합쳐 실제로 집을 세우는 시공팀입니다.
    • 설계도를 다 받기 전에도 받은 부분부터 공사를 시작합니다. 그래서 웹페이지가 한꺼번에 뜨지 않고 위에서부터 조금씩 나타납니다.

렌더링 엔진이 HTML을 받아 화면에 그리기까지의 큰 흐름은 아래 네 단계입니다. 각 단계는 아래 렌더링 동작 과정에서 자세히 다룹니다.

렌더링 엔진의 기본 동작 흐름: DOM 트리 구축을 위한 HTML 파싱, 렌더 트리 구축, 렌더 트리 배치, 렌더 트리 그리기

그림 출처: NAVER D2, 브라우저는 어떻게 동작하는가?

브라우저의 주요 기능 ​

브라우저의 주요 기능은 사용자가 선택한 자원을 서버에 요청하고, 받은 자원을 브라우저 창에 표시하는 것입니다.

  • 자원은 HTML 문서, PDF, 이미지 등 여러 형태가 있습니다.
  • 자원의 위치는 URI(Uniform Resource Identifier) 로 정해집니다. 우리가 주소창에 적는 URL도 URI의 한 종류입니다.
  • 브라우저는 HTML과 CSS 명세(표준 규칙) 에 따라 문서를 해석해서 보여 줍니다.
    • HTML 명세는 현재 브라우저 회사들이 모인 WHATWG 가 "HTML Living Standard"라는 이름으로 관리하고, CSS 명세는 웹 표준화 기구인 W3C(World Wide Web Consortium) 가 정합니다.
    • 예전 브라우저들은 명세를 일부만 따르고 자기만의 방식으로 기능을 넓혔습니다. 그 결과 "이 사이트는 특정 브라우저에서만 잘 보입니다" 같은 심각한 호환성 문제가 생겼고, 지금은 대부분의 브라우저가 표준 명세를 따릅니다.

브라우저마다 생김새는 조금씩 다르지만, 서로 좋은 기능을 따라 하면서 아래 요소들은 거의 공통으로 갖추게 되었습니다.

  • URI를 입력하는 주소 표시줄
  • 이전 / 다음 버튼
  • 북마크(즐겨찾기)
  • 새로 고침 / 정지 버튼
  • 홈 버튼

브라우저의 기본 구조 ​

브라우저는 역할이 다른 7개의 부품으로 나눠 생각할 수 있습니다.

사용자 인터페이스
   │
   ▼
브라우저 엔진 ─────▶ 자료 저장소
   │
   ▼
렌더링 엔진
   ├──▶ 통신
   ├──▶ 자바스크립트 해석기
   └──▶ UI 백엔드

브라우저의 주요 구성 요소: 사용자 인터페이스, 브라우저 엔진, 렌더링 엔진, 통신, 자바스크립트 해석기, UI 백엔드, 자료 저장소

그림 출처: NAVER D2, 브라우저는 어떻게 동작하는가?

구성 요소하는 일
사용자 인터페이스주소 표시줄, 이전/다음 버튼, 북마크 등 사용자가 직접 만지는 부분입니다. 요청한 페이지가 보이는 창을 제외한 나머지 전부입니다.
브라우저 엔진사용자 인터페이스와 렌더링 엔진 사이에서 동작을 제어하는 중간 관리자입니다.
렌더링 엔진요청한 콘텐츠를 화면에 표시합니다. HTML을 요청하면 HTML과 CSS를 파싱해서 화면에 그립니다.
통신HTTP 요청 같은 네트워크 호출을 담당합니다. 운영체제마다 다른 부분을 감춘, 플랫폼 독립적인 인터페이스로 되어 있습니다.
UI 백엔드콤보 박스, 창 같은 기본 위젯을 그립니다. 실제 그리기는 운영체제의 사용자 인터페이스 기능을 빌려 씁니다.
자바스크립트 해석기자바스크립트 코드를 해석하고 실행합니다. 크롬의 V8, 파이어폭스의 SpiderMonkey, 사파리의 JavaScriptCore가 대표적입니다.
자료 저장소쿠키, localStorage, IndexedDB처럼 브라우저가 데이터를 디스크에 저장하는 계층입니다.

참고: 크롬은 탭마다 렌더링 엔진을 별도의 프로세스로 띄웁니다. 한 탭이 멈춰도 다른 탭은 멀쩡한 이유가 이것입니다. 프로세스가 무엇인지는 프로세스와 스레드에서 다룹니다.

URL 입력부터 화면 표시까지 큰 흐름 ​

면접 단골 질문인 "주소창에 URL을 입력하면 무슨 일이 일어나나요?"의 전체 흐름입니다. 렌더링 엔진이 일을 시작하기 전에, 먼저 네트워크 단계가 있습니다.

① URL 해석       https://naver.com  →  프로토콜(https) + 도메인(naver.com) + 경로(/)
      │
② DNS 조회       naver.com  →  IP 주소 (예: 223.130.x.x)
      │
③ TCP 연결       3-way handshake (SYN → SYN+ACK → ACK)
      │
④ TLS 연결       https라면 암호화 키를 주고받음 (인증서 확인)
      │
⑤ HTTP 요청      GET / HTTP/1.1  Host: naver.com
      │
⑥ HTTP 응답      200 OK + HTML 문서
      │
⑦ 렌더링         HTML 파싱 → CSS 파싱 → 렌더 트리 → 레이아웃 → 페인트 → 합성
      │
⑧ 추가 요청      HTML 안의 CSS, JS, 이미지 파일을 다시 요청해서 받아 옴
단계쉽게 말하면
URL 해석주소를 "어떤 방법으로, 어느 집에, 몇 호에" 갈지로 쪼갭니다. 주소가 아니라 검색어면 검색 엔진으로 보냅니다.
DNS 조회사람이 읽는 이름(naver.com)을 컴퓨터가 쓰는 전화번호(IP 주소)로 바꿉니다. 브라우저 캐시, 운영체제 캐시(hosts 파일 포함), DNS 서버 순으로 찾아봅니다.
TCP 연결서버와 "통화 연결"을 맺습니다. 서로 들리는지 세 번 확인하는 과정이라 3-way handshake라고 합니다.
TLS 연결통화 내용을 남이 엿듣지 못하도록 암호를 정합니다. 주소가 https로 시작할 때만 합니다.
HTTP 요청 / 응답"이 페이지 주세요"라고 요청하고, 서버는 상태 코드와 함께 HTML을 돌려줍니다. 자세한 내용은 HTTP 요청 메서드와 HTTP 상태 코드를 참고하세요.
렌더링받은 HTML을 해석해서 화면을 그립니다. 아래에서 자세히 설명합니다.

렌더링이란? ​

렌더링(Rendering) 은 HTML, CSS, 자바스크립트 같은 글자로 된 코드를 사용자가 볼 수 있는 화면(픽셀)으로 바꾸는 과정입니다. 이 일을 하는 부품이 렌더링 엔진입니다.

  • 렌더링 엔진은 기본적으로 HTML, XML 문서와 이미지를 표시할 수 있습니다.
  • PDF 같은 다른 형식은 브라우저에 내장된 뷰어나 확장 기능(플러그인)으로 표시합니다.

렌더링 엔진의 종류 ​

브라우저렌더링 엔진비고
크롬, 엣지, 오페라, 삼성 인터넷Blink2013년 구글이 웹킷에서 갈라져 나와 만든 엔진입니다. 엣지는 2020년부터 Blink를 씁니다.
사파리WebKit (웹킷)애플이 리눅스용 오픈소스 엔진 KHTML을 가져와 맥과 윈도우의 사파리용으로 고친 것이 시작입니다.
파이어폭스Gecko (게코)모질라 재단이 만든 엔진입니다.

아이폰과 아이패드에서는 앱 스토어 규정 때문에 크롬이나 파이어폭스도 내부적으로 웹킷을 써 왔습니다. (2024년부터 유럽 연합 지역에서만 다른 엔진이 허용되었습니다.) 그래서 "아이폰 크롬에서만 화면이 깨진다"면 사파리 문제일 가능성이 큽니다.

렌더링 동작 과정 ​

렌더링 엔진의 기본 흐름은 다음과 같습니다.

  1. HTML을 파싱해서 태그를 모두 DOM 노드로 바꾸고, 이 노드들로 DOM 트리(콘텐츠 트리) 를 만듭니다.
  2. 외부 CSS 파일과 style 태그 안의 스타일을 파싱해서 CSSOM(스타일 규칙 트리) 을 만듭니다.
  3. DOM과 스타일 정보를 합쳐 렌더 트리라는 또 다른 트리를 만듭니다. 렌더 트리에는 색상, 크기 같은 시각적 속성이 붙은 사각형들이 화면에 표시될 순서대로 들어 있습니다.
  4. 배치(레이아웃): 렌더 트리의 각 노드가 화면의 정확히 어디에, 얼마나 크게 놓일지 계산합니다.
  5. 그리기(페인트): UI 백엔드를 이용해 렌더 트리를 돌면서 각 노드를 실제 픽셀로 칠합니다.
 HTML ──파싱──▶ DOM 트리 ──┐
                           ├──어태치먼트──▶ 렌더 트리 ──▶ 레이아웃 ──▶ 페인트 ──▶ 화면
 CSS  ──파싱──▶ CSSOM   ──┘

여기서 중요한 점은 이 과정이 점진적으로 진행된다는 것입니다. 렌더링 엔진은 사용자에게 화면을 조금이라도 빨리 보여 주기 위해, HTML을 끝까지 다 받을 때까지 기다리지 않고 받은 부분부터 배치와 그리기를 시작합니다. 웹페이지에 접속하면 한꺼번에 뜨지 않고 점점 채워지는 것이 바로 이 때문입니다.

DOM이란? ​

DOM(Document Object Model, 문서 객체 모델) 은 브라우저가 HTML 문서를 이해하고 다루기 위해 만든 트리 구조의 객체 모델입니다.

  • 웹페이지 소스를 보면 <html>, <body> 같은 태그가 있습니다. 이 태그들을 자바스크립트가 다룰 수 있는 객체로 바꾼 것이 문서 객체입니다.
  • "모델"은 이 객체들이 서로 어떤 관계(부모, 자식, 형제)인지를 정해 둔 구조라는 뜻입니다.
  • 즉, DOM은 웹 브라우저가 HTML 페이지를 인식하는 방식이며 트리 구조입니다.
  • 자바스크립트에서 document.querySelector('h1')로 요소를 찾거나 글자를 바꿀 수 있는 것도 DOM 덕분입니다. 이 사이트의 다크 모드도 DOM 요소의 속성을 바꾸는 방식으로 동작합니다.

웹킷의 동작 구조와 어태치먼트 ​

웹킷은 위 흐름을 다음 용어로 부릅니다.

일반 용어웹킷에서 부르는 이름
렌더 트리Render Tree (렌더 객체를 renderer라고 부름)
레이아웃Layout
렌더 트리 만들기어태치먼트(Attachment)

아래 그림처럼 HTML 파서가 만든 DOM 트리와 CSS 파서가 만든 스타일 규칙이 어태치먼트에서 만나 렌더 트리가 됩니다.

웹킷의 동작 과정: HTML 파서와 CSS 파서의 결과가 어태치먼트를 거쳐 렌더 트리가 되고, 배치와 그리기를 거쳐 화면에 표시됨

그림 출처: NAVER D2, 브라우저는 어떻게 동작하는가?

어태치먼트: 웹킷이 렌더 트리를 만들기 위해 DOM 노드와 스타일 정보를 연결하는 과정입니다.

파이어폭스(게코)는 같은 과정을 다른 이름으로 부릅니다. 렌더 트리를 프레임 트리(Frame Tree), 레이아웃을 리플로우(Reflow), 어태치먼트를 프레임 생성(Frame Construction) 이라고 합니다. 이름만 다를 뿐 흐름은 같습니다.

파싱과 DOM 트리 구축 ​

파싱(Parsing) 은 렌더링 엔진에서 가장 중요한 과정 중 하나로, 문서를 브라우저가 이해하고 사용할 수 있는 구조로 바꾸는 것입니다.

어휘 분석과 구문 분석 ​

파싱은 두 단계로 이루어집니다.

  1. 어휘 분석(Lexical Analysis): 문서를 의미 있는 최소 단위인 토큰(token) 으로 자릅니다. 국어로 치면 문장을 단어로 끊는 것과 같습니다. 이 일을 하는 것을 어휘 분석기(Lexer, 토크나이저) 라고 합니다.
  2. 구문 분석(Syntax Analysis): 토큰들이 언어의 문법 규칙에 맞게 놓여 있는지 확인하면서 파싱 트리를 만듭니다. 이 일을 하는 것을 구문 분석기(Parser) 라고 합니다.
 <p>안녕 <b>세상</b></p>

 ① 어휘 분석 →  [시작:p] [글자:안녕] [시작:b] [글자:세상] [끝:b] [끝:p]
 ② 구문 분석 →  p
                ├── "안녕"
                └── b
                    └── "세상"

구문 분석기는 어휘 분석기에게 토큰을 하나씩 달라고 요청하고, 그 토큰이 문법 규칙과 맞으면 파싱 트리에 노드로 추가합니다. 끝까지 규칙과 맞지 않는 토큰이 남으면, 그 문서는 유효하지 않고 구문 오류가 있다는 뜻입니다.

일반적인 프로그래밍 언어라면 파싱 트리를 만든 뒤 기계어로 번역(컴파일) 하는 단계가 이어집니다. 하지만 브라우저의 HTML 파싱은 기계어를 만들지 않습니다. HTML 파싱의 최종 결과물은 DOM 트리이고, 이 DOM 트리가 렌더링의 재료가 됩니다.

파서 생성기와 HTML 파서 ​

파서를 직접 손으로 만드는 일은 문법 규칙이 복잡하고 최적화도 어렵기 때문에, 문법 규칙만 주면 파서 코드를 만들어 주는 파서 생성기를 많이 씁니다. 웹킷은 예전에 CSS 파싱에 플렉스(Flex, 어휘 분석기 생성기)와 바이슨(Bison, 구문 분석기 생성기)을 썼습니다. 지금은 크롬과 사파리 모두 속도를 위해 직접 작성한 CSS 파서로 바꿨습니다.

그런데 HTML은 파서 생성기로 만들 수 없습니다. HTML은 아주 관대한 언어라서 문법이 틀려도 화면을 보여 줘야 하기 때문입니다. 그래서 브라우저는 HTML 명세에 정해진 토큰화 알고리즘과 트리 구축 알고리즘을 직접 구현한 전용 파서를 씁니다.

  • 우리가 head 태그를 실수로 빠뜨려도, 파서가 알아서 head 요소를 만들어 줍니다.
  • </p> 닫는 태그를 빼먹어도 다음 <p>가 나오면 앞 문단을 알아서 닫아 줍니다.

이렇게 파싱을 거치면서, 서버에서 받은 글자 덩어리가 브라우저가 이해하고 쉽게 쓸 수 있는 DOM 트리로 바뀝니다.

렌더링 파이프라인 자세히 보기 ​

요즘 브라우저는 앞의 기본 흐름을 더 잘게 나눠서 처리합니다. 이 순서를 중요 렌더링 경로(Critical Rendering Path) 라고도 부릅니다.

단계하는 일비유
1. DOM 생성HTML을 파싱해서 DOM 트리를 만듭니다.설계도를 읽고 방 목록 정리
2. CSSOM 생성CSS를 파싱해서 스타일 규칙 트리를 만듭니다.인테리어 지시서 정리
3. 렌더 트리 생성DOM과 CSSOM을 합칩니다. display: none인 요소나 head처럼 화면에 안 보이는 요소는 빠집니다.실제로 지을 방만 골라 목록 확정
4. 레이아웃각 요소의 위치와 크기를 계산합니다. 박스 크기 계산은 박스 모델 규칙을 따릅니다.줄자로 방 크기와 위치 측정
5. 페인트글자, 색, 그림자, 이미지 등을 레이어별로 픽셀로 칠합니다.벽에 페인트칠
6. 합성(Composite)따로 칠한 레이어들을 순서대로 겹쳐 최종 화면을 만듭니다. GPU가 주로 담당합니다.투명 필름 여러 장을 겹쳐 완성

display: none과 visibility: hidden의 차이: display: none은 렌더 트리에서 아예 빠지므로 자리도 차지하지 않습니다. visibility: hidden은 렌더 트리에 남아 있어서 보이지만 않을 뿐 자리는 그대로 차지합니다.

리플로우와 리페인트 ​

화면이 한 번 그려진 뒤에도 자바스크립트나 사용자 동작 때문에 스타일이 바뀌면, 브라우저는 파이프라인의 일부를 다시 실행합니다.

구분언제 일어나나다시 하는 단계비용
리플로우(Reflow)크기나 위치가 바뀔 때 (width, height, margin, font-size, 창 크기 변경, 요소 추가/삭제)레이아웃 → 페인트 → 합성가장 큼
리페인트(Repaint)모양만 바뀔 때 (color, background-color, visibility)페인트 → 합성중간
합성만transform, opacity 변경 (별도 레이어일 때)합성가장 작음

리플로우는 한 요소만 바뀌어도 그 부모, 자식, 형제의 위치까지 다시 계산해야 할 수 있어서 비용이 큽니다. 크롬에서는 레이아웃을 Layout, 파이어폭스에서는 Reflow라고 부르는데, 같은 말입니다.

리플로우를 줄이는 방법 ​

  • 애니메이션은 transform과 opacity로: left, top으로 움직이면 매 프레임 리플로우가 일어나지만, transform: translateX()는 합성 단계만 다시 합니다. 이 사이트의 애니메이션 효과 글도 참고하세요.
  • 스타일은 한 번에 바꾸기: style.width, style.height를 하나씩 바꾸기보다 클래스 하나를 붙였다 떼는 방식이 좋습니다.
  • 읽기와 쓰기를 섞지 않기: offsetWidth, getBoundingClientRect()처럼 크기를 읽는 코드는 브라우저가 최신 값을 알려 주기 위해 밀린 레이아웃을 즉시 계산하게 만듭니다. 쓰기와 읽기를 번갈아 하면 매번 리플로우가 일어납니다. 이 현상을 강제 동기 레이아웃(Layout Thrashing) 이라고 합니다.
  • 여러 요소는 모아서 추가하기: DocumentFragment에 모아 두었다가 한 번에 DOM에 붙입니다.
  • 영향 범위 줄이기: 자주 움직이는 요소는 position: absolute 또는 fixed로 문서 흐름에서 빼 두면, 다른 요소의 위치 계산에 영향을 덜 줍니다.

script 태그가 파싱을 막는 문제 ​

HTML 파서는 위에서부터 읽다가 <script> 태그를 만나면 파싱을 멈춥니다. 자바스크립트가 document.write()나 DOM 조작으로 문서 구조 자체를 바꿀 수 있기 때문에, 스크립트를 다운로드하고 실행할 때까지 기다려야 하기 때문입니다. 이것을 파서 차단(Parser Blocking) 이라고 합니다.

그래서 예전에는 <script>를 </body> 바로 앞에 두는 것이 정석이었고, 지금은 defer와 async 속성을 씁니다.

일반 <script>
  HTML 파싱   ████████▒▒▒▒▒▒▒▒▒▒████████
  JS 다운로드         ▓▓▓▓▓▓
  JS 실행                   ░░░░  (다운로드와 실행 동안 파싱이 멈춤)

<script async>
  HTML 파싱   ██████████████▒▒▒▒████████
  JS 다운로드     ▓▓▓▓▓▓▓▓▓▓
  JS 실행                   ░░░░  (다운로드가 끝나는 즉시 실행, 이때만 파싱 멈춤)

<script defer>
  HTML 파싱   ██████████████████████████
  JS 다운로드     ▓▓▓▓▓▓▓▓▓▓
  JS 실행                               ░░░░  (파싱이 다 끝난 뒤 실행)
방식다운로드실행 시점실행 순서어울리는 경우
일반 <script>파싱을 멈추고 받음받자마자적힌 순서거의 없음 (body 끝에 둘 때만)
async파싱과 동시에받자마자 (파싱 중일 수도 있음)보장 안 됨광고, 방문자 통계처럼 다른 코드와 상관없는 독립 스크립트
defer파싱과 동시에HTML 파싱이 끝난 뒤, DOMContentLoaded 직전적힌 순서DOM을 다루는 대부분의 스크립트

CSS도 비슷한 문제가 있습니다. CSS는 HTML 파싱을 막지는 않지만, CSSOM이 완성될 때까지 렌더 트리를 만들 수 없으므로 렌더링을 막습니다(Render Blocking). 그래서 CSS는 head에 두어 최대한 빨리 받게 하는 것이 좋습니다.

코드로 감 잡기: 태그를 트리로 바꾸기 ​

Python에 내장된 html.parser로 HTML을 한 줄씩 읽으면서 DOM 트리 모양을 직접 출력해 봅니다. 여는 태그를 만나면 한 칸 들어가고, 닫는 태그를 만나면 한 칸 나옵니다.

python
from html.parser import HTMLParser

html = """
<html>
  <body>
    <h1>안녕하세요</h1>
    <p>브라우저는 <b>태그</b>를 트리로 바꿉니다</p>
  </body>
</html>
"""

class TreeBuilder(HTMLParser):
    def __init__(self):
        super().__init__()
        self.depth = 0          # 지금 몇 단계 안쪽에 있는지

    def handle_starttag(self, tag, attrs):
        print("  " * self.depth + tag)     # 여는 태그 = 새 노드
        self.depth += 1                     # 자식은 한 칸 안쪽

    def handle_endtag(self, tag):
        self.depth -= 1                     # 닫는 태그 = 부모로 돌아감

    def handle_data(self, data):
        if data.strip():                    # 공백만 있는 줄은 건너뜀
            print("  " * self.depth + f'"{data.strip()}"')

TreeBuilder().feed(html)

실행 결과:

html
  body
    h1
      "안녕하세요"
    p
      "브라우저는"
      b
        "태그"
      "를 트리로 바꿉니다"

이번에는 리플로우가 왜 비싼지, 읽기와 쓰기를 섞으면 무슨 일이 생기는지 흉내 내 봅니다. 실제 브라우저처럼 "스타일을 바꾸면 표시만 해 두고, 크기를 읽을 때 밀린 레이아웃을 계산"하는 규칙을 단순하게 만든 모델입니다.

python
# 레이아웃을 다시 계산하는 횟수 비교 (브라우저 동작을 흉내 낸 모델)
class FakeBrowser:
    def __init__(self):
        self.dirty = False      # 스타일이 바뀌어서 레이아웃이 낡았는지
        self.layout_count = 0   # 레이아웃(리플로우)을 몇 번 했는지
        self.width = 100

    def set_width(self, value):         # 스타일 쓰기: 표시만 해 둠
        self.width = value
        self.dirty = True

    def read_offset_width(self):        # 크기 읽기: 낡았으면 즉시 레이아웃
        if self.dirty:
            self.layout_count += 1
            self.dirty = False
        return self.width

# 1) 쓰기와 읽기를 번갈아 하는 경우
b1 = FakeBrowser()
for i in range(100):
    b1.set_width(i)
    b1.read_offset_width()
print("번갈아 읽고 쓰기:", b1.layout_count, "번 리플로우")

# 2) 읽기를 먼저 모아서 하고, 쓰기는 나중에 몰아서 하는 경우
b2 = FakeBrowser()
w = b2.read_offset_width()
for i in range(100):
    b2.set_width(w + i)
b2.read_offset_width()   # 다음 화면 그리기 직전에 한 번만
print("읽기 먼저, 쓰기 몰아서:", b2.layout_count, "번 리플로우")

실행 결과:

번갈아 읽고 쓰기: 100 번 리플로우
읽기 먼저, 쓰기 몰아서: 1 번 리플로우

같은 일을 해도 순서만 바꾸면 레이아웃 계산이 100번에서 1번으로 줄어듭니다.

면접에서 자주 나오는 질문 ​

Q. 주소창에 URL을 입력하면 어떤 일이 일어나나요? URL을 해석하고, DNS로 도메인의 IP 주소를 찾고, 서버와 TCP 연결(https면 TLS까지)을 맺은 뒤 HTTP 요청을 보냅니다. 서버가 HTML을 응답하면 렌더링 엔진이 HTML과 CSS를 파싱해 DOM과 CSSOM을 만들고, 이를 합친 렌더 트리로 레이아웃과 페인트를 거쳐 화면에 그립니다.

Q. DOM이 무엇인가요? HTML 문서를 브라우저와 자바스크립트가 다룰 수 있도록 객체로 바꿔 트리 구조로 표현한 모델입니다. 자바스크립트는 DOM을 통해 요소를 찾고, 내용과 스타일을 바꿉니다.

Q. 리플로우와 리페인트의 차이는 무엇인가요? 리플로우는 요소의 크기나 위치가 바뀌어 레이아웃을 다시 계산하는 것이고, 리페인트는 색처럼 모양만 바뀌어 다시 칠하는 것입니다. 리플로우가 일어나면 리페인트도 따라오므로 리플로우가 더 비쌉니다. 애니메이션은 transform, opacity를 써서 둘 다 피하는 것이 좋습니다.

Q. script 태그의 async와 defer는 어떻게 다른가요? 둘 다 HTML 파싱과 동시에 스크립트를 내려받습니다. async는 다운로드가 끝나는 즉시 실행하고 실행 순서를 보장하지 않습니다. defer는 HTML 파싱이 모두 끝난 뒤 적힌 순서대로 실행합니다. DOM을 다루는 스크립트에는 보통 defer를 씁니다.

Q. 웹페이지가 한꺼번에 뜨지 않고 조금씩 나타나는 이유는 무엇인가요? 렌더링 엔진이 사용자에게 빨리 보여 주기 위해 HTML을 끝까지 다 받을 때까지 기다리지 않고, 받은 부분부터 파싱하고 배치와 그리기를 점진적으로 진행하기 때문입니다.

정리 ​

개념한 줄 요약
브라우저의 역할서버에 자원을 요청하고, 받은 자원을 표준 명세에 따라 해석해 화면에 표시
기본 구조 7요소사용자 인터페이스, 브라우저 엔진, 렌더링 엔진, 통신, UI 백엔드, JS 해석기, 자료 저장소
렌더링 엔진크롬/엣지는 Blink, 사파리는 WebKit, 파이어폭스는 Gecko
큰 흐름URL 해석 → DNS 조회 → TCP/TLS 연결 → HTTP 요청/응답 → 렌더링
렌더링 파이프라인DOM → CSSOM → 렌더 트리 → 레이아웃 → 페인트 → 합성
DOM브라우저가 HTML을 인식하는 트리 구조의 객체 모델
어태치먼트웹킷에서 DOM 노드와 스타일 정보를 연결해 렌더 트리를 만드는 과정
파싱어휘 분석(토큰으로 자르기) + 구문 분석(문법 확인하며 트리 만들기). HTML 파싱의 결과는 DOM 트리
리플로우 / 리페인트크기·위치 변경은 레이아웃부터, 색 변경은 페인트부터 다시 함
async / defer파서 차단을 피하는 방법. 순서가 중요하면 defer
점진적 렌더링다 받기 전에 받은 부분부터 그려서 화면이 조금씩 나타남