Skip to content

Split View: URL을 입력하고 엔터를 누르면 벌어지는 일: 브라우저·DNS·TCP·TLS·HTTP·렌더링 전 구간 투어

|

URL을 입력하고 엔터를 누르면 벌어지는 일: 브라우저·DNS·TCP·TLS·HTTP·렌더링 전 구간 투어

들어가며 — 1초 안에 벌어지는 대서사시

"주소창에 URL을 입력하고 엔터를 누르면 무슨 일이 일어나나요?" 이 질문은 면접 단골이지만, 사실 그 이유가 있습니다. 이 한 줄짜리 동작 안에 웹이라는 시스템의 거의 모든 층이 압축되어 있기 때문입니다. DNS, 라우팅, 전송 계층, 암호화, 애플리케이션 프로토콜, 그리고 렌더링 엔진까지. 하나를 제대로 설명하려면 전부를 조금씩 알아야 합니다.

이 글은 그 여정을 순서대로 따라갑니다. 브라우저가 URL을 해석하는 순간부터 화면에 첫 픽셀이 그려지는 순간까지, 각 단계에서 실제로 무엇이 오가는지 짚어 보겠습니다. 예시 주소는 https://example.com/store/cart?id=42 라고 하겠습니다.

1단계 — URL 파싱과 사전 처리

엔터를 누른 직후, 브라우저는 먼저 주소창에 입력된 문자열이 무엇인지 판단합니다. 이것이 URL인지, 아니면 검색어인지부터 결정합니다. 공백이 있거나 점(.)이 없으면 기본 검색 엔진으로 넘기고, URL처럼 보이면 파싱을 시작합니다.

URL은 여러 부분으로 나뉩니다.

  https://example.com:443/store/cart?id=42#top
  └─┬─┘   └────┬────┘└┬┘└───┬────┘└──┬──┘└┬┘
  스킴      호스트   포트   경로     쿼리  프래그먼트
  • 스킴(scheme): https. 어떤 프로토콜로 통신할지 정합니다.
  • 호스트(host): example.com. 접속할 서버의 도메인 이름입니다.
  • 포트(port): 생략하면 https는 443, http는 80이 기본입니다.
  • 경로(path), 쿼리(query), 프래그먼트(fragment): 서버 안에서 어떤 자원을 원하는지, 어떤 파라미터를 붙이는지, 문서 내 어디로 스크롤할지를 나타냅니다.

이 단계에서 브라우저는 몇 가지 최적화를 이미 수행합니다. HSTS(HTTP Strict Transport Security) 목록에 있는 도메인이면 http로 입력해도 강제로 https로 바꿉니다. 그리고 브라우저 캐시, 서비스 워커, HTTP 캐시에 이 자원이 있는지도 확인해서, 있으면 네트워크를 아예 건너뛸 수도 있습니다.

2단계 — DNS 해석: 이름을 주소로

호스트 이름 example.com은 사람을 위한 것입니다. 네트워크는 IP 주소로 통신하므로, 도메인 이름을 IP 주소로 바꾸는 과정이 필요합니다. 이것이 DNS(Domain Name System) 해석입니다.

브라우저는 여러 층의 캐시를 순서대로 뒤집니다. 캐시에서 답을 찾으면 그 즉시 끝나므로, 실제 질의는 캐시가 모두 비었을 때만 발생합니다.

  1. 브라우저 자체 DNS 캐시를 봅니다.
  2. 없으면 운영체제의 리졸버 캐시(그리고 hosts 파일)를 봅니다.
  3. 그래도 없으면 설정된 재귀 리졸버(recursive resolver), 보통 ISP나 공용 DNS(예: 8.8.8.8)에게 묻습니다.

재귀 리졸버가 답을 모르면, 이제 진짜 재귀 질의가 시작됩니다. 리졸버는 여러 권한 서버를 차례로 방문합니다.

  재귀 리졸버
     │  1) "example.com 의 IP는?"
  루트 서버      -> ".com 담당은 저쪽 TLD 서버야"
  .com TLD 서버  -> "example.com 담당 네임서버는 여기야"
  권한 네임서버   -> "example.com 은 93.184.216.34 야"
  재귀 리졸버가 결과를 캐시하고 브라우저에 반환

이 과정에서 각 응답에는 **TTL(Time To Live)**이 붙어 있습니다. TTL 동안은 리졸버가 그 답을 캐시에 보관하므로, 같은 도메인을 다시 물으면 루트까지 갈 필요 없이 빠르게 답합니다. DNS가 대체로 빠르게 느껴지는 이유가 바로 이 다층 캐시 덕분입니다.

성능을 위해 브라우저는 페이지 로딩 전에 미리 DNS를 조회해 두는 DNS 프리페치도 합니다. 링크에 마우스를 올리는 순간 뒤에서 조용히 해석을 시작해 두는 식입니다.

3단계 — TCP 3-way 핸드셰이크: 연결을 세우다

IP 주소를 알았으니 이제 그 서버와 연결을 맺어야 합니다. https는 신뢰성 있는 전송 계층인 TCP 위에서 동작하므로, 데이터를 보내기 전에 먼저 TCP 연결을 세웁니다. 이것이 유명한 3-way 핸드셰이크입니다.

  클라이언트                         서버
     │ ── SYN (seq=x) ─────────────►│   "연결하고 싶어"
     │                              │
     │ ◄──── SYN-ACK (seq=y, ack=x+1)│  "좋아, 나도 준비됐어"
     │                              │
     │ ── ACK (ack=y+1) ───────────►│   "확인, 시작하자"
     ▼                              ▼
      이제 양방향 데이터 전송 가능

세 번의 왕복 중 두 번의 메시지가 오간 뒤부터 실질적으로 연결이 성립됩니다. 각 단계에서 시퀀스 번호(seq)를 교환하는데, 이는 이후 데이터의 순서를 맞추고 유실을 감지하는 기준이 됩니다. 이 핸드셰이크는 최소 1 RTT(round-trip time, 왕복 시간)를 소모합니다. 서버가 지구 반대편에 있다면 이 한 번의 왕복만으로도 수백 밀리초가 들 수 있습니다.

참고로 최신 프로토콜인 HTTP/3은 TCP 대신 UDP 기반의 QUIC을 사용해 이 연결 수립과 다음 단계인 암호화를 하나로 합쳐 지연을 줄입니다. 하지만 개념을 이해하기에는 전통적인 TCP + TLS 조합이 가장 명확하므로, 이 글은 그 흐름을 따릅니다.

4단계 — TLS 핸드셰이크: 안전한 통로 만들기

TCP 연결이 섰지만, 그 위로 흐르는 데이터는 아직 평문입니다. https의 's'는 TLS(Transport Layer Security)를 뜻하며, 실제 HTTP 데이터를 보내기 전에 암호화된 통로를 먼저 만듭니다. TLS 핸드셰이크가 하는 일은 크게 세 가지입니다. 서버가 진짜 그 서버인지 인증하고, 통신을 암호화할 열쇠를 교환하며, 사용할 암호 방식을 협상합니다.

TLS 1.3 기준으로 흐름을 단순화하면 이렇습니다.

  클라이언트                              서버
     │ ── ClientHello ──────────────────►│  지원하는 암호 스위트, 키 공유 목록
     │                                   │
     │ ◄── ServerHello, Certificate ─────│  선택한 암호, 인증서, 키 공유
     │      + Finished                   │
     │                                   │
     │ ── Finished ─────────────────────►│  검증 완료
     ▼                                   ▼
      이후 모든 HTTP 데이터는 암호화되어 흐른다

핵심 단계를 풀어 보면 이렇습니다.

  • 인증서 검증: 서버는 자신의 인증서를 보냅니다. 브라우저는 이 인증서가 신뢰된 인증 기관(CA)의 서명을 받은 것인지, 도메인 이름이 일치하는지, 만료되지 않았는지를 확인합니다. 하나라도 어긋나면 그 무서운 "안전하지 않은 연결" 경고가 뜹니다.
  • 키 교환: 양쪽은 공개키 암호(예: ECDHE)를 이용해, 도청자가 오가는 메시지를 다 봐도 알아낼 수 없는 공유 비밀을 만들어 냅니다. 이 비밀에서 실제 데이터를 암호화할 대칭키가 유도됩니다.
  • 암호 스위트 협상: 어떤 암호화·해시 알고리즘 조합을 쓸지 정합니다.

TLS 1.3은 이 전체를 1 RTT로 줄였고, 예전에 방문한 서버라면 0-RTT 재개까지 가능합니다. 이전 버전인 TLS 1.2가 2 RTT를 쓰던 것과 비교하면 큰 개선입니다. 인증서 검증, 암호 스위트, 핸드셰이크 흐름을 직접 눈으로 실험해 보고 싶다면 이 사이트의 인증·보안 실험실에서 TLS와 관련 개념을 다뤄 볼 수 있습니다.

5단계 — HTTP 요청 보내기

암호화된 통로가 완성되었으니, 드디어 브라우저가 원하던 것을 요청할 차례입니다. 브라우저는 HTTP 요청 메시지를 만들어 보냅니다. HTTP/1.1 기준으로 요청은 대략 이런 텍스트 형태입니다.

GET /store/cart?id=42 HTTP/1.1
Host: example.com
User-Agent: Mozilla/5.0 ...
Accept: text/html,application/xhtml+xml
Accept-Encoding: gzip, br
Cookie: session=abc123
Connection: keep-alive

각 줄의 의미를 짚어 봅시다.

  • 요청 라인: 메서드(GET), 경로(/store/cart?id=42), 프로토콜 버전.
  • Host 헤더: 한 IP에 여러 사이트가 올라가 있는 경우(가상 호스팅), 어떤 도메인을 원하는지 알려 줍니다.
  • Accept 계열 헤더: 어떤 콘텐츠 형식과 압축을 받을 수 있는지 서버에 알립니다.
  • Cookie 헤더: 이전에 서버가 심어 둔 쿠키를 되돌려 보내, 로그인 상태 같은 것을 유지합니다.

HTTP/2와 HTTP/3에서는 이 헤더들이 사람이 읽는 텍스트가 아니라 이진 프레임으로 압축되어 전송되고, 한 연결에서 여러 요청을 동시에(멀티플렉싱) 보낼 수 있습니다. 하지만 논리적으로 담기는 정보는 위와 같습니다.

6단계 — 서버의 처리와 응답

요청은 네트워크를 건너 서버에 도착합니다. 그런데 "서버"는 대개 단일 기계가 아닙니다. 요청은 보통 여러 계층을 거칩니다.

  요청 --> [CDN / 엣지 캐시] --> [로드 밸런서] --> [리버스 프록시]
              │(캐시 히트면 여기서 바로 응답)
              --> [웹/애플리케이션 서버] --> [데이터베이스 / 캐시]
  • CDN과 엣지 캐시: 정적 자원(이미지, CSS, JS)이나 캐시 가능한 페이지는 사용자와 가까운 엣지 서버가 바로 응답합니다. 그러면 원본 서버까지 갈 필요가 없어 훨씬 빠릅니다.
  • 로드 밸런서: 트래픽을 여러 서버 인스턴스에 분산합니다.
  • 애플리케이션 서버: 실제 로직을 실행합니다. 라우팅을 하고, 데이터베이스에서 데이터를 읽고, HTML을 렌더링하거나 JSON을 만듭니다.

처리가 끝나면 서버는 HTTP 응답을 돌려줍니다. 응답의 첫 줄에는 상태 코드가 실립니다.

HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
Content-Encoding: br
Cache-Control: max-age=3600
Set-Cookie: session=abc123; HttpOnly; Secure

<!DOCTYPE html>
<html> ... </html>

상태 코드는 결과를 세 자리 숫자로 요약합니다. 200은 성공, 301·302는 리다이렉트, 404는 자원 없음, 500은 서버 오류입니다. 이 숫자들의 정확한 의미와 뉘앙스가 궁금하다면 HTTP 상태 코드 도감에서 각 코드를 하나씩 살펴볼 수 있습니다. 응답 본문은 대개 gzip이나 br로 압축되어 오므로, 브라우저는 먼저 압축을 풀어야 합니다.

7단계 — HTML 파싱과 DOM 만들기

브라우저가 HTML 바이트를 받기 시작하면, 처음부터 끝까지 다 받기를 기다리지 않고 도착하는 대로 파싱을 시작합니다. 파싱의 목표는 문서를 트리 구조인 **DOM(Document Object Model)**으로 바꾸는 것입니다.

  HTML 바이트 --> 토큰화 --> 노드 생성 --> DOM 트리

파싱 도중 브라우저는 추가로 필요한 자원을 만납니다. <link>로 참조된 CSS, <script>로 참조된 자바스크립트, <img>의 이미지 등입니다. 이때 중요한 두 가지 성질이 있습니다.

  • CSS는 렌더링을 막습니다(render-blocking): 브라우저는 스타일을 모두 알기 전에는 화면을 안전하게 그릴 수 없습니다. 그래서 CSS를 받아 파싱해 **CSSOM(CSS Object Model)**을 만들 때까지 렌더링을 미룹니다.
  • 스크립트는 파싱을 막을 수 있습니다(parser-blocking): 일반 <script>는 만나는 순간 HTML 파싱을 멈추고 스크립트를 내려받아 실행합니다. 스크립트가 DOM을 바꿀 수 있기 때문입니다. 이를 피하려고 asyncdefer 속성을 붙여 파싱과 병행하거나 나중으로 미룹니다.

브라우저는 이 와중에도 프리로드 스캐너를 돌려, 본격적으로 파싱하기 전에 앞으로 필요할 자원들을 미리 내려받기 시작합니다. 덕분에 스크립트가 파싱을 막는 동안에도 다른 자원 다운로드는 계속됩니다.

8단계 — 크리티컬 렌더링 경로: 픽셀까지

DOM과 CSSOM이 준비되면, 브라우저는 이 둘을 합쳐 화면을 그리는 일련의 단계를 거칩니다. 이 전체 과정을 **크리티컬 렌더링 경로(Critical Rendering Path)**라고 부릅니다.

  DOM + CSSOM --> 렌더 트리 --> 레이아웃 --> 페인트 --> 합성

각 단계는 이런 일을 합니다.

  • 렌더 트리(Render Tree): DOM과 CSSOM을 결합하되, 실제로 화면에 보이는 노드만 담습니다. display: none인 요소는 여기서 빠집니다.
  • 레이아웃(Layout / Reflow): 각 요소가 화면 어디에, 얼마만 한 크기로 놓일지 기하학적 위치를 계산합니다. 뷰포트 크기가 바뀌면 이 계산을 다시 해야 합니다.
  • 페인트(Paint): 각 요소의 픽셀을 실제로 칠합니다. 색, 텍스트, 이미지, 그림자 등을 채웁니다.
  • 합성(Composite): 여러 레이어로 나뉜 페인트 결과를 올바른 순서로 합쳐 최종 화면을 만듭니다. GPU가 이 일을 가속합니다.

여기서 성능과 직결되는 개념이 **리플로우(reflow)**와 **리페인트(repaint)**입니다. 자바스크립트로 요소의 크기나 위치를 바꾸면 레이아웃부터 다시 계산되는 리플로우가 일어나고, 색만 바꾸면 레이아웃은 건드리지 않고 다시 칠하는 리페인트만 일어납니다. 리플로우가 리페인트보다 비싸므로, 부드러운 애니메이션을 위해서는 레이아웃을 유발하지 않는 속성(transform, opacity 등)을 쓰는 것이 유리합니다. 이 속성들은 합성 단계에서만 처리되어 레이아웃과 페인트를 건너뛸 수 있기 때문입니다.

전체 흐름 다시 보기

지금까지의 여정을 한눈에 정리하면 이렇습니다.

  1. URL 파싱          입력 문자열을 스킴/호스트/경로로 분해
  2. DNS 해석          도메인 이름 -> IP (다층 캐시 + 재귀 질의)
  3. TCP 핸드셰이크    3-way 로 신뢰성 있는 연결 수립 (1 RTT)
  4. TLS 핸드셰이크    인증 + 키 교환 + 암호 협상 (1 RTT)
  5. HTTP 요청         메서드/헤더/쿠키를 담아 전송
  6. 서버 처리         CDN/LB/앱서버/DB 를 거쳐 응답 생성
  7. HTML 파싱         바이트 -> DOM, CSS -> CSSOM
  8. 렌더링            렌더 트리 -> 레이아웃 -> 페인트 -> 합성

각 단계는 그 자체로 책 한 권 분량의 깊이를 가지고 있지만, 큰 그림에서 보면 결국 하나의 목표를 향합니다. "사람이 읽을 수 있는 주소"를 "화면 위의 픽셀"로 바꾸는 것입니다.

마치며

주소창에 URL을 입력하고 엔터를 누르는 그 짧은 순간에, 이름 해석, 연결 수립, 신원 인증, 암호화, 데이터 전송, 문서 파싱, 화면 렌더링이라는 완전히 다른 성격의 작업들이 정확한 순서로 맞물려 돌아갑니다. 이 흐름을 이해하면 성능 문제를 만났을 때 어느 단계를 의심해야 할지, 보안 경고가 떴을 때 무엇이 어긋난 것인지 훨씬 빠르게 감을 잡을 수 있습니다.

다음에 페이지 로딩이 느리게 느껴진다면, 이 여덟 단계 중 어디에서 시간이 새고 있을지 상상해 보세요. DNS일까, 핸드셰이크일까, 서버 처리일까, 아니면 렌더링일까. 그 질문을 던질 수 있다는 것만으로도 이미 웹을 한 층 더 깊이 보게 된 것입니다.

참고 자료

What Happens When You Type a URL and Hit Enter: A Full-Stack Tour from Browser to Pixel

Introduction — An Epic That Unfolds in Under a Second

"What happens when you type a URL into the address bar and press Enter?" It is a cliché interview question, but there is a good reason it endures. That single one-line action compresses nearly every layer of the web into one motion: DNS, routing, the transport layer, encryption, an application protocol, and a rendering engine. To explain any one of them well, you have to know a little about all of them.

This post walks that journey in order. From the instant the browser interprets your URL to the moment the first pixel lands on screen, we will trace what actually travels back and forth at each step. Our example address will be https://example.com/store/cart?id=42.

Step 1 — URL Parsing and Preprocessing

The moment you hit Enter, the browser first decides what the text in the address bar even is. Is it a URL, or is it a search query? If it has spaces or no dots, it goes to the default search engine; if it looks like a URL, parsing begins.

A URL breaks into several parts.

  https://example.com:443/store/cart?id=42#top
  └─┬─┘   └────┬────┘└┬┘└───┬────┘└──┬──┘└┬┘
  scheme    host    port   path     query fragment
  • Scheme: https. Which protocol to speak.
  • Host: example.com. The domain name of the server to reach.
  • Port: omitted here, so it defaults to 443 for https and 80 for http.
  • Path, query, fragment: which resource you want inside the server, which parameters to attach, and where to scroll within the document.

The browser already performs a few optimizations here. If the domain is on the HSTS (HTTP Strict Transport Security) list, even an http entry is forcibly rewritten to https. It also checks whether the resource is in the browser cache, a service worker, or the HTTP cache — and if so, it may skip the network entirely.

Step 2 — DNS Resolution: Turning a Name into an Address

The hostname example.com is for humans. Networks communicate with IP addresses, so we need to translate the domain name into one. That is DNS (Domain Name System) resolution.

The browser checks several layers of cache in order. If any layer has the answer, resolution ends immediately — an actual query only happens when every cache is empty.

  1. It checks the browser's own DNS cache.
  2. If that misses, it checks the operating system's resolver cache (and the hosts file).
  3. Still nothing? It asks the configured recursive resolver — usually your ISP's or a public DNS such as 8.8.8.8.

If the recursive resolver does not know the answer either, the real recursive query begins. The resolver visits a chain of authoritative servers.

  Recursive resolver
     │  1) "What is the IP of example.com?"
  Root server       -> "The .com people are over at that TLD server"
  .com TLD server   -> "The nameserver for example.com is here"
  Authoritative NS  -> "example.com is 93.184.216.34"
  Resolver caches the result and returns it to the browser

Each answer carries a TTL (Time To Live). For the length of the TTL, the resolver keeps that answer cached, so asking for the same domain again is fast — no trip back to the root required. This multi-layer caching is exactly why DNS usually feels instant.

For performance, browsers also do DNS prefetching — resolving names ahead of the actual load. Hover over a link and the browser may quietly start resolving it in the background.

Step 3 — The TCP Three-Way Handshake: Establishing a Connection

Now that we have an IP address, we need a connection to that server. Because https runs over TCP, the reliable transport layer, we establish a TCP connection before sending any data. This is the famous three-way handshake.

  Client                              Server
     │ ── SYN (seq=x) ─────────────►│   "I want to connect"
     │                              │
     │ ◄──── SYN-ACK (seq=y, ack=x+1)│  "OK, I'm ready too"
     │                              │
     │ ── ACK (ack=y+1) ───────────►│   "Confirmed, let's go"
     ▼                              ▼
      Bidirectional data can now flow

The connection is effectively established after two of the three messages have crossed. Each step exchanges sequence numbers (seq), which become the basis for ordering later data and detecting loss. This handshake costs at least 1 RTT (round-trip time). If the server sits on the other side of the planet, that single round trip alone can take hundreds of milliseconds.

For reference, the newer HTTP/3 uses UDP-based QUIC instead of TCP and folds connection setup and the next step — encryption — into one, cutting latency. But the classic TCP + TLS combination is the clearest way to understand the concepts, so this post follows that flow.

Step 4 — The TLS Handshake: Building a Secure Channel

The TCP connection stands, but the data flowing over it is still plaintext. The 's' in https means TLS (Transport Layer Security), and before any real HTTP data goes out, we build an encrypted channel first. The TLS handshake does three things: it authenticates that the server is who it claims to be, it exchanges the keys used to encrypt the traffic, and it negotiates which cipher to use.

Simplified to TLS 1.3, the flow looks like this.

  Client                                Server
     │ ── ClientHello ────────────────►│  supported cipher suites, key shares
     │                                 │
     │ ◄── ServerHello, Certificate ───│  chosen cipher, certificate, key share
     │      + Finished                 │
     │                                 │
     │ ── Finished ───────────────────►│  verification complete
     ▼                                 ▼
      From here on, all HTTP data flows encrypted

Unpacking the key steps:

  • Certificate verification: The server sends its certificate. The browser checks that it is signed by a trusted certificate authority (CA), that the domain name matches, and that it has not expired. If any of these fail, you get that scary "your connection is not secure" warning.
  • Key exchange: Using public-key cryptography (such as ECDHE), both sides derive a shared secret that an eavesdropper cannot recover even while watching every message go by. A symmetric key for encrypting the actual data is derived from that secret.
  • Cipher suite negotiation: They agree on which combination of encryption and hashing algorithms to use.

TLS 1.3 cut all of this down to 1 RTT, and for a server you have visited before, even 0-RTT resumption is possible — a big improvement over the 2 RTT of the older TLS 1.2. If you want to experiment with certificate verification, cipher suites, and handshake flows firsthand, this site's Auth & Security Lab lets you play with TLS and related concepts.

Step 5 — Sending the HTTP Request

With the encrypted channel in place, the browser can finally ask for what it came for. It builds and sends an HTTP request message. In HTTP/1.1 terms, a request is roughly this piece of text.

GET /store/cart?id=42 HTTP/1.1
Host: example.com
User-Agent: Mozilla/5.0 ...
Accept: text/html,application/xhtml+xml
Accept-Encoding: gzip, br
Cookie: session=abc123
Connection: keep-alive

What each line means:

  • Request line: the method (GET), the path (/store/cart?id=42), and the protocol version.
  • Host header: when many sites share one IP (virtual hosting), this tells the server which domain you want.
  • Accept-family headers: tell the server which content formats and compressions you can accept.
  • Cookie header: sends back cookies the server previously set, preserving things like a login session.

In HTTP/2 and HTTP/3 these headers are not human-readable text but compressed binary frames, and one connection can carry many requests at once (multiplexing). But the information conveyed is the same as above.

Step 6 — The Server's Processing and Response

The request crosses the network and arrives at the server. Except "the server" is rarely a single machine. The request usually passes through several layers.

  Request --> [CDN / edge cache] --> [load balancer] --> [reverse proxy]
                 │(on a cache hit, responds right here)
                 --> [web/app server] --> [database / cache]
  • CDN and edge cache: static assets (images, CSS, JS) and cacheable pages are served directly by an edge server near the user, so there is no need to reach the origin at all — much faster.
  • Load balancer: spreads traffic across multiple server instances.
  • Application server: runs the actual logic. It routes, reads data from a database, and renders HTML or produces JSON.

Once processing finishes, the server returns an HTTP response. Its first line carries the status code.

HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
Content-Encoding: br
Cache-Control: max-age=3600
Set-Cookie: session=abc123; HttpOnly; Secure

<!DOCTYPE html>
<html> ... </html>

A status code summarizes the outcome in three digits. 200 is success, 301 and 302 are redirects, 404 is not found, 500 is a server error. If you are curious about the precise meaning and nuance of these numbers, the HTTP Status Code Reference lets you inspect each one. The response body usually arrives compressed with gzip or br, so the browser has to decompress it first.

Step 7 — Parsing HTML and Building the DOM

As the browser begins receiving HTML bytes, it does not wait for the whole thing to arrive — it starts parsing as bytes stream in. The goal of parsing is to turn the document into a tree structure, the DOM (Document Object Model).

  HTML bytes --> tokenize --> create nodes --> DOM tree

During parsing the browser encounters additional resources it needs: CSS referenced by <link>, JavaScript referenced by <script>, images in <img>, and so on. Two properties matter a lot here.

  • CSS is render-blocking: the browser cannot safely paint the screen before it knows all the styles. So it defers rendering until it has fetched and parsed the CSS into the CSSOM (CSS Object Model).
  • Scripts can be parser-blocking: a plain <script> stops HTML parsing the moment it is encountered, downloads, and runs — because the script might modify the DOM. To avoid this you add async or defer to run it alongside parsing or to postpone it.

Even so, the browser runs a preload scanner that starts downloading resources it will soon need before full parsing reaches them. Thanks to that, other downloads keep going even while a script blocks the parser.

Step 8 — The Critical Rendering Path: Down to Pixels

Once the DOM and CSSOM are ready, the browser goes through a sequence of steps to combine them and draw the screen. This whole process is called the critical rendering path.

  DOM + CSSOM --> render tree --> layout --> paint --> composite

What each step does:

  • Render tree: combines the DOM and CSSOM, but only includes nodes that are actually visible. Elements with display: none are dropped here.
  • Layout (reflow): computes the geometry — where and how large each element sits on screen. When the viewport size changes, this has to be recomputed.
  • Paint: fills in the actual pixels of each element — colors, text, images, shadows.
  • Composite: merges the painted layers in the correct order into the final screen. The GPU accelerates this.

The performance-critical concepts here are reflow and repaint. Change an element's size or position with JavaScript and you trigger a reflow that recomputes layout; change only its color and you get a repaint that redraws without touching layout. Reflow is more expensive than repaint, so for smooth animation it is best to use properties that do not trigger layout (transform, opacity, and the like). Those are handled only in the composite step, which lets the browser skip layout and paint.

The Whole Flow, One More Time

Here is the entire journey at a glance.

  1. URL parsing       split the input string into scheme/host/path
  2. DNS resolution    domain name -> IP (multi-layer cache + recursive query)
  3. TCP handshake     establish a reliable connection via 3-way (1 RTT)
  4. TLS handshake     authenticate + key exchange + cipher negotiation (1 RTT)
  5. HTTP request      send method/headers/cookies
  6. Server processing generate the response through CDN/LB/app server/DB
  7. HTML parsing      bytes -> DOM, CSS -> CSSOM
  8. Rendering         render tree -> layout -> paint -> composite

Each step is deep enough to fill a book, but from the big-picture view they all serve one goal: turning "a human-readable address" into "pixels on a screen."

Wrapping Up

In the brief instant you type a URL and press Enter, wildly different kinds of work — name resolution, connection setup, identity verification, encryption, data transfer, document parsing, and screen rendering — mesh together in exactly the right order. Understanding this flow means that when you hit a performance problem, you know which step to suspect, and when a security warning pops up, you know what went wrong — far faster.

The next time a page feels slow to load, imagine where among these eight steps the time is leaking. Is it DNS, the handshake, server processing, or rendering? Simply being able to ask that question means you already see the web one layer deeper.

References