πŸš€ Complete Deep Dive

How Browsers Actually Work

From HTTP Request to Painting Pixels β€” Understanding the Critical Rendering Path and Optimization Techniques

The Journey Overview

When you type a URL and press Enter, a complex sequence of events unfolds. Understanding this journey is crucial for optimizing web performance.

THE BROWSER'S JOURNEY
  1. URL ENTERED
       ↓
  2. DNS LOOKUP (Domain β†’ IP Address)
       ↓
  3. TCP CONNECTION (3-way handshake)
       ↓
  4. TLS HANDSHAKE (if HTTPS)
       ↓
  5. HTTP REQUEST SENT
       ↓
  6. SERVER PROCESSES & RESPONDS
       ↓
  7. BROWSER RECEIVES HTML
       ↓
  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
  β”‚           CRITICAL RENDERING PATH BEGINS                  β”‚
  β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
  β”‚  8. HTML PARSING β†’ DOM Construction                       β”‚
  β”‚       ↓                                                   β”‚
  β”‚  9. CSS PARSING β†’ CSSOM Construction                      β”‚
  β”‚       ↓                                                   β”‚
  β”‚  10. JavaScript Execution (can block!)                    β”‚
  β”‚       ↓                                                   β”‚
  β”‚  11. RENDER TREE = DOM + CSSOM                            β”‚
  β”‚       ↓                                                   β”‚
  β”‚  12. LAYOUT (Reflow) - Calculate positions & sizes        β”‚
  β”‚       ↓                                                   β”‚
  β”‚  13. PAINT - Fill in pixels                               β”‚
  β”‚       ↓                                                   β”‚
  β”‚  14. COMPOSITE - Layer management                         β”‚
  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
       ↓
  15. πŸŽ‰ PAGE IS VISIBLE TO USER!

DNS Resolution

When you type https://example.com, the browser needs to find the IP address of that server. This process can take 20-120ms!

DNS RESOLUTION FLOW
   Browser: "What's the IP for example.com?"

   1. Browser Cache      β†’ Check if we visited recently
          ↓ (miss)
   2. OS Cache           β†’ Check operating system's cache
          ↓ (miss)
   3. Router Cache       β†’ Check your router
          ↓ (miss)
   4. ISP DNS Server     β†’ Your Internet Provider's DNS
          ↓ (miss)
   5. Recursive Search:
      β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
      β”‚  Root DNS (.com, .org, .net servers)            β”‚
      β”‚       ↓                                         β”‚
      β”‚  TLD Server (Top Level Domain - .com)           β”‚
      β”‚       ↓                                         β”‚
      β”‚  Authoritative DNS (example.com's own server)   β”‚
      β”‚       ↓                                         β”‚
      β”‚  IP Address: 93.184.216.34                      β”‚
      β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

   ⏱️ This process can take 20-120ms!

DNS Optimization Techniques

Technique How it Works
DNS Prefetch <link rel="dns-prefetch" href="//api.example.com">
Preconnect <link rel="preconnect" href="https://fonts.googleapis.com">
Reduce DNS lookups Use fewer external domains
DNS Caching Browser/OS cache frequently visited domains

TCP Handshake

TCP (Transmission Control Protocol) ensures reliable, ordered delivery of data. Before sending anything, both parties must agree to communicate through a 3-way handshake.

TCP 3-WAY HANDSHAKE
      CLIENT (Browser)                           SERVER
            β”‚                                       β”‚
            β”‚                                       β”‚
   Step 1:  β”‚ ─────────── SYN ──────────────────▢  β”‚
   "Hey,    β”‚     seq=100 (random number)          β”‚
   wanna    β”‚     "I want to connect!"             β”‚
   talk?"   β”‚                                       β”‚
            β”‚                                       β”‚
            β”‚                                       β”‚  Step 2:
            β”‚  ◀────────── SYN-ACK ─────────────── β”‚  "Sure! I hear you,
            β”‚     seq=300, ack=101                  β”‚   and I want to
            β”‚     "Got it! I also want to connect!" β”‚   connect too!"
            β”‚                                       β”‚
            β”‚                                       β”‚
   Step 3:  β”‚ ─────────── ACK ──────────────────▢  β”‚
   "Great,  β”‚     seq=101, ack=301                  β”‚
   let's    β”‚     "Confirmed! Let's go!"            β”‚
   go!"     β”‚                                       β”‚
            β”‚                                       β”‚
            β”‚ ═══════════════════════════════════  β”‚
            β”‚     CONNECTION ESTABLISHED!           β”‚

   ⏱️ Time: ~1 RTT (Round Trip Time)
   πŸ“ Typical: 20-100ms depending on distance
πŸ’‘ Why 3 Steps?

Step 1 (SYN): Client proves it can SEND
Step 2 (SYN-ACK): Server proves it can SEND and RECEIVE
Step 3 (ACK): Client proves it can RECEIVE

TLS Handshake

After TCP connection is established, if using HTTPS, we need another handshake to establish encryption.

TLS 1.2 vs TLS 1.3

⏱️ TLS 1.2 (Slower)

2 RTT for handshake
Multiple round trips for key exchange
Time: ~60-100ms

⚑ TLS 1.3 (Faster)

1 RTT for handshake
Key share sent in ClientHello
Time: ~30-50ms
0-RTT for session resumption!

FULL CONNECTION TIMELINE (HTTPS with TLS 1.2)
   TIME    CLIENT                                    SERVER

    β”‚      ──────── DNS Query ────────────────────▢
    β”‚      ◀─────── DNS Response ─────────────────
  0ms      DNS Resolution: ~50ms

    β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€

    β”‚      ──────── SYN ──────────────────────────▢
    β”‚      ◀─────── SYN-ACK ──────────────────────
    β”‚      ──────── ACK ──────────────────────────▢
  50ms     TCP Handshake: ~30ms (1 RTT)

    β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€

    β”‚      ──────── ClientHello ──────────────────▢
    β”‚      ◀─────── ServerHello, Certificate ─────
    β”‚      ──────── Key Exchange, Finished ───────▢
    β”‚      ◀─────── Finished ─────────────────────
  140ms    TLS Handshake: ~60ms (2 RTT for TLS 1.2)

    β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€

    β”‚      ══════════ SECURE CONNECTION ══════════

    β”‚      ──────── HTTP Request ─────────────────▢
    β”‚      ◀─────── HTTP Response ────────────────

   ⏱️ Total before first byte: ~200ms minimum!

   With TLS 1.3:  ~140ms (saves one RTT)
   With 0-RTT:    ~80ms (connection reuse)

HTML Parsing & DOM Construction

The browser transforms raw bytes into a structured DOM tree through a multi-step pipeline.

1
Bytes β†’ Characters
Raw bytes (3C 68 74 6D 6C...) are decoded using UTF-8 into readable characters (<html>...)
2
Characters β†’ Tokens
Tokenizer reads characters and produces tokens (StartTag, EndTag, Character, etc.)
3
Tokens β†’ Nodes
Tokens are converted into DOM nodes with properties and methods
4
Nodes β†’ DOM Tree
Nodes are connected into a tree structure using a stack-based algorithm

Parser Blocking

PARSER BLOCKING SCENARIOS
  <html>
    <body>
      <h1>Title</h1>               βœ… Parsed
      <script src="app.js">        πŸ›‘ STOP! Must fetch & execute
      </script>
      <p>Content below</p>         ⏸️ WAITING... (not parsed yet)
    </body>
  </html>

  WHY does script block?
  Script might call document.write() which can CHANGE the HTML!
  Parser can't continue until it knows what the script will do.

Preload Scanner

πŸ” The Preload Scanner

While the main parser is blocked, a secondary scanner keeps looking ahead for resources to fetch in parallel (images, CSS, scripts). This can significantly speed up page load!

CSSOM Construction

Unlike DOM which mirrors HTML structure, CSSOM mirrors CSS structure.

CSSOM OBJECT MODEL
  document.styleSheets
       β”‚
       β”‚  StyleSheetList (array-like)
       β”‚
       β”œβ”€β”€ [0] CSSStyleSheet (user-agent styles)
       β”‚         β”‚
       β”‚         └── .cssRules: CSSRuleList
       β”‚
       β”œβ”€β”€ [1] CSSStyleSheet (your styles.css)
       β”‚         β”‚
       β”‚         β”œβ”€β”€ .cssRules: CSSRuleList
       β”‚         β”‚       β”œβ”€β”€ [0] CSSStyleRule
       β”‚         β”‚       β”‚        β”œβ”€β”€ .selectorText: "body"
       β”‚         β”‚       β”‚        └── .style: { margin: "0" }
       β”‚         β”‚       β”‚
       β”‚         β”‚       β”œβ”€β”€ [1] CSSMediaRule (@media query)
       β”‚         β”‚       β”‚        └── .cssRules: (nested rules)
       β”‚         β”‚       β”‚
       β”‚         β”‚       └── [2] CSSKeyframesRule
       β”‚         β”‚
       β”‚         └── .href: "https://example.com/styles.css"
       β”‚
       └── [2] CSSStyleSheet (inline <style>)

CSS is RENDER-BLOCKING

⚠️ The Fundamental Rule

DOM ready βœ“ + CSSOM loading ⏳ = NO PAINT 🚫
DOM ready βœ“ + CSSOM ready βœ“ = CAN PAINT βœ…

Why? To prevent FOUC (Flash Of Unstyled Content). The browser will show a blank screen rather than unstyled content.

Multiple CSS Files

If you have 3 CSS files and one loads in 100ms but others take 4 seconds, CSSOM waits for ALL render-blocking CSS files. First paint happens after the SLOWEST file loads.

Async CSS Loading

HTML
<!-- Media trick - load CSS without blocking -->
<link rel="stylesheet" href="styles.css" 
      media="print" onload="this.media='all'">

<!-- Preload + onload technique -->
<link rel="preload" href="styles.css" as="style" 
      onload="this.rel='stylesheet'">

<!-- Fallback for browsers without JS -->
<noscript><link rel="stylesheet" href="styles.css"></noscript>

Render Tree

The Render Tree = DOM nodes that are VISIBLE + their COMPUTED STYLES. This is where DOM and CSSOM come together!

RENDER TREE CONSTRUCTION
  STEP 1: Start with DOM tree
  ─────────────────────────────

       DOM                   CSSOM

        html                  body { margin: 0; }
          β”‚                   h1 { color: blue; }
       β”Œβ”€β”€β”΄β”€β”€β”                .hidden { display: none; }
     head   body              p::before { content: "β†’"; }
              β”‚
         β”Œβ”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”
        h1  .hidden  p

  STEP 2: Walk DOM, attach computed styles
  ─────────────────────────────────────────

  For EACH DOM node:
   1. Is it visible? (display: none = skip!)
   2. Compute all styles (cascade + inheritance)
   3. Create Render Object (attach styles)

  STEP 3: Result = Render Tree
  ─────────────────────────────

  RenderView (viewport)
       β”‚
  RenderBlock (body)
   styles: { margin: 0 }
       β”‚
   β”Œβ”€β”€β”€β”΄β”€β”€β”€β”€β”
   β”‚        β”‚
  RenderBlock    RenderBlock
  (h1)           (p)
   β”‚              β”‚
   β”‚          β”Œβ”€β”€β”€β”΄β”€β”€β”€β”€β”
   β”‚          β”‚        β”‚
  RenderText RenderInline RenderText
  "Title"    (::before)   "Content"
             content: "β†’"

  ❌ .hidden element NOT in Render Tree!
     (display: none removes it completely)
DOM TREE vs RENDER TREE (Visual Comparison)
   DOM TREE (Complete structure):          RENDER TREE (Visual only):

          Document                              RenderView
              β”‚                                     β”‚
           <html>                              RenderBlock
              β”‚                                  (viewport)
        β”Œβ”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”                               β”‚
        β”‚           β”‚                          RenderBlock
     <head>      <body>                          (body)
        β”‚           β”‚                               β”‚
   β”Œβ”€β”€β”€β”€β”΄β”€β”€β”€β”€β”     ...                    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”
   β”‚    β”‚    β”‚                            β”‚        β”‚        β”‚
 <meta><title><style>              RenderBlock RenderBlock RenderBlock
   ❌    ❌     ❌                    (header)   (main)    (p)
                                        β”‚          β”‚           β”‚
  (Not in render tree -             RenderText    β”‚      RenderText
   non-visual elements)             ("Header")    β”‚
                                                  β”‚
                                           β”Œβ”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”
                                           β”‚             β”‚
                                      RenderBlock   RenderBlock
                                         (p)        (hidden-p)
                                           β”‚             ❌
                                      β”Œβ”€β”€β”€β”€β”΄β”€β”€β”€β”€β”   (display:none
                                      β”‚         β”‚    NOT in tree!)
                                 RenderInline RenderText
                                  (::before)  ("Visible")

Style Computation (The Cascade)

HOW COMPUTED STYLES ARE CALCULATED
  For element: <p class="intro" id="welcome">Hello</p>

  STEP 1: Find all matching rules
  ──────────────────────────────────

  Matches:
  p { color: black; font-size: 16px; }           /* (0,0,0,1) */
  .intro { color: blue; line-height: 1.5; }      /* (0,0,1,0) */
  #welcome { color: green; }                     /* (0,1,0,0) */
  p.intro { font-weight: bold; }                 /* (0,0,1,1) */

  STEP 2: Apply cascade (specificity order)
  ────────────────────────────────────────────

  Specificity = (inline, id, class, element)

  color: black   (0,0,0,1) β†’ overwritten
  color: blue    (0,0,1,0) β†’ overwritten
  color: green   (0,1,0,0) β†’ WINS! (highest specificity)

  STEP 3: Inherit from parent (for inheritable props)
  ─────────────────────────────────────────────────────

  Parent (body): font-family: Arial;
  Element (p):   inherits font-family: Arial

  STEP 4: Apply defaults for missing properties
  ─────────────────────────────────────────────────

  display: not specified β†’ default: inline (for p: block)
  margin: not specified β†’ default: browser stylesheet

  FINAL COMPUTED STYLE:
  ─────────────────────
  {
    color: green,          // from #welcome (highest specificity)
    font-size: 16px,       // from p
    line-height: 1.5,      // from .intro
    font-weight: bold,     // from p.intro
    font-family: Arial,    // inherited from body
    display: block,        // browser default for p
    margin: 1em 0,         // browser default for p
    ...                    // all 300+ CSS properties!
  }

Specificity Calculator

SPECIFICITY RULES
  SPECIFICITY FORMAT: (inline, ID, class, element)

  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
  β”‚                                                             β”‚
  β”‚  style=""        β†’  (1,0,0,0)  ← Inline ALWAYS wins!         β”‚
  β”‚  #id             β†’  (0,1,0,0)                               β”‚
  β”‚  .class          β†’  (0,0,1,0)                               β”‚
  β”‚  [attr]          β†’  (0,0,1,0)  ← Same as class              β”‚
  β”‚  :pseudo-class   β†’  (0,0,1,0)  ← Same as class              β”‚
  β”‚  element         β†’  (0,0,0,1)                               β”‚
  β”‚  ::pseudo-elem   β†’  (0,0,0,1)  ← Same as element            β”‚
  β”‚  *               β†’  (0,0,0,0)  ← Universal = no specificity β”‚
  β”‚                                                             β”‚
  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

  EXAMPLES:

  p                        β†’  (0,0,0,1)
  p.intro                  β†’  (0,0,1,1)
  div p.intro              β†’  (0,0,1,2)
  #header .nav a           β†’  (0,1,1,1)
  #header .nav a:hover     β†’  (0,1,2,1)
  div#main p.text span     β†’  (0,1,1,3)

  COMPARISON (left to right):
  (0,1,0,0) beats (0,0,99,99) β†’ IDs beat any number of classes!

What's NOT in the Render Tree?

What IS in the Render Tree (even if not visible)?

display:none vs visibility:hidden vs opacity:0

Property In Render Tree Takes Space Clickable Animatable
display: none ❌ No ❌ No ❌ No ❌ No
visibility: hidden βœ… Yes βœ… Yes ❌ No ⚠️ Jumps
opacity: 0 βœ… Yes βœ… Yes βœ… Yes βœ… Smooth

Layout (Reflow)

Layout calculates exact position (x, y) and size (width, height) for every element, transforming relative values to absolute pixels.

WHAT LAYOUT DOES
  Render Tree knows:                      Layout calculates:

  RenderBlock (div)                       RenderBlock (div)
  styles: {                               layout: {
    width: 50%,        ← 50% of WHAT?       x: 200,            ← Exact X position
    padding: 2em,      ← how many pixels?   y: 100,            ← Exact Y position
    margin: auto       ← what value?        width: 600,        ← 50% of 1200px = 600px
  }                                         height: 400,       ← Calculated from content
                                            padding: 32,       ← 2em Γ— 16px = 32px
                                            margin-left: 200   ← auto calculated
                                          }

  Layout transforms RELATIVE values β†’ ABSOLUTE pixel values

  β€’ %     β†’ pixels (based on parent)
  β€’ em    β†’ pixels (based on font-size)
  β€’ auto  β†’ pixels (calculated from context)
  β€’ vw/vh β†’ pixels (based on viewport)
  β€’ calc()β†’ pixels (computed result)
THE BOX MODEL
  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
  β”‚              MARGIN                     β”‚
  β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚
  β”‚  β”‚            BORDER                 β”‚  β”‚
  β”‚  β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚  β”‚
  β”‚  β”‚  β”‚          PADDING            β”‚  β”‚  β”‚
  β”‚  β”‚  β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚  β”‚  β”‚
  β”‚  β”‚  β”‚  β”‚                       β”‚  β”‚  β”‚  β”‚
  β”‚  β”‚  β”‚  β”‚     CONTENT BOX       β”‚  β”‚  β”‚  β”‚
  β”‚  β”‚  β”‚  β”‚    (width Γ— height)   β”‚  β”‚  β”‚  β”‚
  β”‚  β”‚  β”‚  β”‚                       β”‚  β”‚  β”‚  β”‚
  β”‚  β”‚  β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚  β”‚  β”‚
  β”‚  β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚  β”‚
  β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

  box-sizing: content-box (default)
  β†’ width/height applies to content only
  β†’ Total = width + padding + border
  β†’ Example: width: 200px; padding: 20px; border: 5px;
    Total = 200 + 20 + 20 + 5 + 5 = 250px

  box-sizing: border-box (recommended!)
  β†’ width/height includes padding and border
  β†’ Total = exactly what you specify
  β†’ Example: width: 200px; padding: 20px; border: 5px;
    Content = 200 - 20 - 20 - 5 - 5 = 150px
    Total = 200px (as specified!)

Layout Algorithm

LAYOUT ALGORITHM STEPS
  STEP 1: Start at root (viewport)
  ─────────────────────────────────
  Viewport size is known (e.g., 1920Γ—1080)
  This is the "containing block" for the document

  viewport = { width: 1920, height: 1080, x: 0, y: 0 }

  STEP 2: Calculate widths (TOP-DOWN)
  ──────────────────────────────────────
  Width often depends on parent, so go parent β†’ child

  Parent: width = 1000px
  Child: width = 50%
  β†’ Child computed width = 500px

  STEP 3: Calculate heights (BOTTOM-UP)
  ───────────────────────────────────────
  Height often depends on children, so go child β†’ parent

  Child 1: height = 100px
  Child 2: height = 150px
  Child 3: height = 80px
  β†’ Parent height = 100 + 150 + 80 = 330px

  STEP 4: Calculate positions (x, y coordinates)
  ──────────────────────────────────────────────────
  Based on:
  β€’ Display mode (block, inline, flex, grid)
  β€’ Position property (static, relative, absolute, fixed)
  β€’ Float property
  β€’ Margins (including margin collapse!)

Layout Modes (Formatting Contexts)

DIFFERENT LAYOUT MODES
  BLOCK FORMATTING CONTEXT (BFC)
  ══════════════════════════════
  Elements with display: block, flex, grid, table

  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
  β”‚                    Block 1 (full width)                   β”‚
  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
  β”‚                    Block 2 (full width)                   β”‚
  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

  Rules:
  β€’ Each block on its own line (vertical stacking)
  β€’ Width fills container (unless specified)
  β€’ Vertical margins COLLAPSE between siblings

  ────────────────────────────────────────────────────────────

  INLINE FORMATTING CONTEXT (IFC)
  ═══════════════════════════════
  Elements with display: inline, inline-block

  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
  β”‚ This is [inline1] text with [inline2] elements that [in-  β”‚
  β”‚ line3] wrap to the next line when they run out of space.  β”‚
  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

  Rules:
  β€’ Elements flow horizontally (like text)
  β€’ Wrap to next line when no space
  β€’ Vertical margins DON'T apply (use line-height)

  ────────────────────────────────────────────────────────────

  FLEXBOX LAYOUT
  ══════════════
  display: flex

  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
  β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”     β”‚
  β”‚ β”‚  Flex 1  β”‚ β”‚  Flex 2  β”‚ β”‚  Flex 3  β”‚ β”‚  Flex 4  β”‚     β”‚
  β”‚ β”‚  flex:1  β”‚ β”‚  flex:2  β”‚ β”‚  flex:1  β”‚ β”‚  flex:1  β”‚     β”‚
  β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜     β”‚
  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

  ────────────────────────────────────────────────────────────

  GRID LAYOUT
  ═══════════
  display: grid; grid-template-columns: 1fr 2fr 1fr;

  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
  β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”           β”‚
  β”‚ β”‚   1    β”‚ β”‚          2           β”‚ β”‚   3    β”‚           β”‚
  β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”˜           β”‚
  β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”           β”‚
  β”‚ β”‚   4    β”‚ β”‚          5           β”‚ β”‚   6    β”‚           β”‚
  β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”˜           β”‚
  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Margin Collapse

⚠️ Margin Collapse - A Layout Quirk

In Block Formatting Context, vertical margins can collapse! If Box 1 has margin-bottom: 30px and Box 2 has margin-top: 20px, the gap is only 30px (larger one wins), not 50px!

What Triggers Layout?

LAYOUT TRIGGERS
  CSS PROPERTY CHANGES (that affect geometry):
  β€’ width, height, min-*, max-*
  β€’ margin, padding, border-width
  β€’ top, left, right, bottom (positioned elements)
  β€’ font-size, font-family, font-weight
  β€’ display, position, float
  β€’ flex-*, grid-*

  DOM CHANGES:
  β€’ Adding/removing elements
  β€’ Changing text content
  β€’ Moving elements

  READING LAYOUT PROPERTIES (Forces sync layout!):
  β€’ offsetTop, offsetLeft, offsetWidth, offsetHeight
  β€’ clientTop, clientLeft, clientWidth, clientHeight
  β€’ scrollTop, scrollLeft, scrollWidth, scrollHeight
  β€’ getComputedStyle() (some properties)
  β€’ getBoundingClientRect()

  ⚠️ Reading these FORCES browser to calculate layout immediately!

Layout Thrashing

LAYOUT THRASHING EXPLAINED
  ❌ BAD: Causes layout thrashing!

  boxes.forEach(box => {
    const width = box.offsetWidth;    // READ β†’ Forces layout!
    box.style.width = (width + 10) + 'px';  // WRITE β†’ Invalidates
    // Next iteration: READ again β†’ Forces NEW layout!
  });

  Timeline:
  [Layout][Layout][Layout][Layout][Layout] ... 100 times!
  If 100 boxes: 100 layout calculations = ~1 SECOND of blocking!

  ─────────────────────────────────────────────────────────────

  βœ… GOOD: Batch reads, then batch writes

  // BATCH READ (one layout calculation)
  const widths = Array.from(boxes).map(box => box.offsetWidth);

  // BATCH WRITE (no layout during writes)
  boxes.forEach((box, i) => {
    box.style.width = (widths[i] + 10) + 'px';
  });

  Timeline:
  [Layout]...[Paint]
  Total: ~10ms instead of 1 second!

  ─────────────────────────────────────────────────────────────

  VISUALIZATION:

  ❌ Layout Thrashing:
  R W L R W L R W L R W L R W L R W L R W L R W L R W L R W L
  β””β”€β”΄β”€β”΄β”€β”΄β”€β”΄β”€β”΄β”€β”΄β”€β”΄β”€β”΄β”€β”΄β”€β”΄β”€β”΄β”€β”΄β”€β”΄β”€β”΄β”€β”΄β”€β”΄β”€β”΄β”€β”΄β”€β”΄β”€β”΄β”€β”΄β”€β”΄β”€β”΄β”€β”΄β”€β”΄β”€β”΄β”€β”΄β”€β”΄β”€β”΄β”€β”˜
             Many layout calculations interleaved!

  βœ… Batched:
  R R R R R R R R R R β”‚ L β”‚ W W W W W W W W W W
  └───── Reads β”€β”€β”€β”€β”€β”€β”€β”˜   └────── Writes β”€β”€β”€β”€β”€β”€β”˜
                    Single layout!
❌ BAD: Read-Write Loop
boxes.forEach(box => {
  const width = box.offsetWidth;  // READ
  box.style.width = width + 'px'; // WRITE
  // Repeat = Layout every iteration!
});
βœ… GOOD: Batched
// Batch reads
const widths = boxes.map(b => b.offsetWidth);
// Batch writes
boxes.forEach((box, i) => {
  box.style.width = widths[i] + 'px';
});

Paint

Paint converts Layout boxes into actual pixels using drawing commands (Paint Records). This is where the browser draws colors, images, text, shadows, and everything visual!

WHAT IS PAINT?
  Layout tells us:                      Paint tells us:

  "This box is at                       "Fill this area with
   position (100, 50)                    blue (#0066ff), draw
   with size 200Γ—100"                    a 2px black border,
                                         render text 'Hello'
                                         in Arial 16px"

  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”                    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
  β”‚                 β”‚                    β”‚β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ”‚
  β”‚   x: 100        β”‚           β†’        β”‚β–ˆ               β–ˆβ”‚
  β”‚   y: 50         β”‚                    β”‚β–ˆ    Hello      β–ˆβ”‚
  β”‚   width: 200    β”‚                    β”‚β–ˆ               β–ˆβ”‚
  β”‚   height: 100   β”‚                    β”‚β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ”‚
  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
  Just geometry                          Actual pixels!
PAINT RECORDS (Drawing Commands)
  CSS:
  .button {
    background: linear-gradient(#4CAF50, #388E3C);
    border: 2px solid #2E7D32;
    border-radius: 8px;
    box-shadow: 0 4px 6px rgba(0,0,0,0.3);
    color: white;
    font: bold 16px Arial;
  }

  Paint Records Generated:

  1. DrawShadow(
       x: 100, y: 54,           // Offset for shadow
       blur: 6,
       color: rgba(0,0,0,0.3)
     )

  2. DrawRoundedRect(
       x: 100, y: 50,
       width: 200, height: 50,
       radius: 8,
       fill: LinearGradient(#4CAF50 β†’ #388E3C)
     )

  3. StrokeRoundedRect(
       x: 100, y: 50,
       width: 200, height: 50,
       radius: 8,
       strokeWidth: 2,
       strokeColor: #2E7D32
     )

  4. DrawText(
       text: "Click Me",
       x: 150, y: 80,           // Centered position
       font: "bold 16px Arial",
       color: #FFFFFF
     )

  These commands are executed in ORDER to produce the final pixels!

Paint Order (Stacking Context)

PAINT ORDER
  Elements are painted in a SPECIFIC ORDER (back to front):

  PAINT ORDER (within each stacking context):

  1. Background color of element
  2. Background image
  3. Border
  4. Children (in DOM order)
  5. Outline

  STACKING ORDER (z-axis, back to front):

     BACK (painted first)
        ↓
  1. Root element background
  2. Positioned elements with negative z-index
  3. Non-positioned block elements (in DOM order)
  4. Non-positioned float elements
  5. Non-positioned inline elements (text, images)
  6. Positioned elements with z-index: 0 or auto
  7. Positioned elements with positive z-index
        ↓
     FRONT (painted last, on top)

What Triggers Paint?

Property Type Layout Paint Composite
width, height, margin, padding βœ“ βœ“ βœ“
color, background, box-shadow βœ— βœ“ βœ“
transform, opacity βœ— βœ— βœ“

Paint Cost

PAINT COST: WHAT'S EXPENSIVE?
  🟒 CHEAP (fast to paint):
  ──────────────────────────
  β€’ Solid color backgrounds
  β€’ Simple borders
  β€’ Simple text

  .simple {
    background: #fff;
    border: 1px solid #ccc;
    color: #333;
  }

  ─────────────────────────────────────────────────────────────

  🟑 MEDIUM (more work):
  ──────────────────────
  β€’ Gradients
  β€’ Border-radius
  β€’ Images

  .medium {
    background: linear-gradient(to bottom, #fff, #eee);
    border-radius: 10px;
  }

  ─────────────────────────────────────────────────────────────

  πŸ”΄ EXPENSIVE (slow to paint):
  ─────────────────────────────
  β€’ Box shadows (especially large blur radius)
  β€’ Text shadows
  β€’ Filters (blur, drop-shadow)
  β€’ Clip-path (complex shapes)
  β€’ Mix-blend-mode

  .expensive {
    box-shadow: 0 10px 50px rgba(0,0,0,0.5);  // Large blur!
    filter: blur(5px) drop-shadow(10px 10px 10px #000);
    clip-path: polygon(50% 0%, 100% 50%, 50% 100%, 0% 50%);
  }

  ─────────────────────────────────────────────────────────────

  PAINT AREA MATTERS TOO:

  Small area with expensive effect:
  β”Œβ”€β”€β”€β”€β”
  β”‚blurβ”‚  ~1ms (small area, still okay)
  β””β”€β”€β”€β”€β”˜

  Large area with expensive effect:
  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
  β”‚                  BLUR ENTIRE PAGE                          β”‚
  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
  ~50ms+ (huge area = SLOW!)

  Paint cost = Complexity Γ— Area

Paint Layers

WITH vs WITHOUT LAYERS
  WITHOUT LAYERS (Single Surface):
  ─────────────────────────────────
  Any change = Repaint EVERYTHING on that surface

  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
  β”‚ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ”‚
  β”‚ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ Change here ═══════════════▢ Repaint ALL! β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ”‚
  β”‚ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ”‚
  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

  ─────────────────────────────────────────────────────────────

  WITH LAYERS (Multiple Surfaces):
  ────────────────────────────────
  Each layer is painted independently!

  Layer 3 (animated element):
  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
  β”‚  Button (hover) β”‚ ◀── Only this layer repaints!
  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

  Layer 2 (fixed header):
  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
  β”‚                    Header                                   β”‚
  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

  Layer 1 (main content):
  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
  β”‚ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ”‚
  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

  Change in Layer 3 = Only repaint Layer 3! (much faster)
πŸ’‘ DevTools: Visualize Paint

Paint Flashing: DevTools β†’ Cmd+Shift+P β†’ "Show paint flashing" β†’ Green flash shows repainted areas
Layer Borders: Rendering tab β†’ Check "Layer borders" β†’ See compositor layers
Performance Panel: Record and see paint timing in the flame chart

Compositing

Compositing is the final step β€” GPU combines all painted layers into the final image. This runs on a separate compositor thread!

WHAT IS COMPOSITING?
  After Paint creates bitmaps (textures) for each layer:

  Layer Textures (in GPU memory):

  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
  β”‚   Layer 1    β”‚  β”‚   Layer 2    β”‚  β”‚   Layer 3    β”‚
  β”‚  (content)   β”‚  β”‚   (header)   β”‚  β”‚   (modal)    β”‚
  β”‚              β”‚  β”‚              β”‚  β”‚              β”‚
  β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚  β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚  β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚
  β”‚  β”‚ Bitmap β”‚  β”‚  β”‚  β”‚ Bitmap β”‚  β”‚  β”‚  β”‚ Bitmap β”‚  β”‚
  β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚  β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚  β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
         β”‚                  β”‚                 β”‚
         β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                            β”‚
                            β–Ό
                   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                   β”‚   COMPOSITOR    β”‚
                   β”‚                 β”‚
                   β”‚  β€’ Position     β”‚
                   β”‚  β€’ Transform    β”‚
                   β”‚  β€’ Opacity      β”‚
                   β”‚  β€’ Blend        β”‚
                   β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                            β”‚
                            β–Ό
                   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                   β”‚  FINAL FRAME    β”‚
                   β”‚   (to screen)   β”‚
                   β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

  Key insight: GPU can transform/blend textures WITHOUT repainting!
COMPOSITOR THREAD vs MAIN THREAD
   MAIN THREAD                    COMPOSITOR THREAD

   β€’ JavaScript                   β€’ Layer composition
   β€’ DOM manipulation             β€’ Transform animations
   β€’ Style calculation            β€’ Opacity animations
   β€’ Layout                       β€’ Scrolling
   β€’ Paint (generate records)     β€’ Pinch-zoom

   Can be BLOCKED by             NEVER blocked by
   heavy JavaScript!              JavaScript!

   ───────────────────────────────────────────────────────────────

   Scenario: Heavy JavaScript running (500ms)

   Main Thread:
   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
   β”‚ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ JavaScript (500ms) β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ β”‚
   β”‚ BLOCKED - Can't do layout/paint!                              β”‚
   β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

   Compositor Thread:
   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
   β”‚ β–‘β–‘β–‘ Composite β–‘β–‘β–‘ Composite β–‘β–‘β–‘ Composite β–‘β–‘β–‘ Composite β–‘β–‘β–‘   β”‚
   β”‚ Still running! Smooth scrolling! 60fps animations!            β”‚
   β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

   Transform/opacity animations stay SMOOTH even when
   JavaScript is blocking the main thread!

Compositor-Only Operations (GPU Accelerated)

These operations can be performed by the GPU without repainting:

GPU OPERATIONS
  1. TRANSLATE (Move position)
  ─────────────────────────────
  transform: translateX(100px) translateY(50px);

  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”                     β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”
  β”‚  Layer  β”‚   ───────────▢      β”‚  Layer  β”‚
  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                     β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
  Original                        Moved (GPU just repositions!)

  2. SCALE (Resize)
  ──────────────────
  transform: scale(1.5);

  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”                     β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
  β”‚  Layer  β”‚   ───────────▢      β”‚     Layer     β”‚
  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                     β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
  Original                        Scaled (GPU stretches texture!)

  3. ROTATE
  ─────────
  transform: rotate(45deg);

  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”                        ◇─────────◇
  β”‚  Layer  β”‚   ───────────▢       β—‡β”‚  Layer  β”‚β—‡
  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                        ◇─────────◇
  Original                        Rotated (GPU rotates texture!)

  4. OPACITY (Transparency)
  ───────────────────────────
  opacity: 0.5;

  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”                     β”Œ ─ ─ ─ ─ ─┐
  β”‚β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ”‚   ───────────▢      β”‚β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β”‚
  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                     β”” ─ ─ ─ ─ β”€β”˜
  Solid                           Semi-transparent
                                  (GPU blends with background!)

  ALL OF THESE:
  β€’ Don't require repaint!
  β€’ Run on compositor thread (off main thread!)
  β€’ Are GPU accelerated (super fast!)
  β€’ Can hit 60fps even with heavy JS!

What Creates Layers?

LAYER PROMOTION TRIGGERS
  AUTOMATIC LAYER PROMOTION:

  βœ“ 3D transforms
    transform: translateZ(0)
    transform: translate3d(x, y, z)
    transform: rotateX/Y/Z()

  βœ“ CSS animation/transition on transform or opacity
    .box { transition: transform 0.3s; }
    @keyframes slide { to { transform: translateX(100px); } }

  βœ“ position: fixed
    Fixed elements often get their own layer

  βœ“ will-change property
    will-change: transform, opacity;

  βœ“ <video> and <canvas> elements
    Media always gets own layer

  βœ“ CSS filter or backdrop-filter
    filter: blur(10px);

  βœ“ Element overlapping a composited layer
    If A is layered and B overlaps A, B might get a layer too!

  βœ“ opacity < 1
    opacity: 0.99 triggers layer creation!

Layer Tree Visualization

3D VIEW OF LAYERS
  Example page with multiple layers:

             β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
            β•±β”‚  Video    β”‚    Layer 5 (front)
           β•± β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
          β•±
         β•±  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
        β•±  β•±β”‚   Modal   β”‚     Layer 4
       β•±  β•± β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
      β•±  β•±
     β•±  β•±  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
    β•±  β•±  β•±β”‚   Card    β”‚      Layer 3
   β•±  β•±  β•± β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
  β•±  β•±  β•±
    β•±  β•±  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
   β•±  β•±  β•±β”‚  Header   β”‚       Layer 2
     β•±  β•± β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
       β•±
  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
  β”‚              Main Content                 β”‚  Layer 1 (back)
  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

  GPU composites these layers together each frame!
  Change in one layer = Only that layer updates!

Layer Memory Cost

MEMORY CALCULATION
  Layer size: 1920 Γ— 1080 pixels
  Color depth: 4 bytes per pixel (RGBA)

  Memory = 1920 Γ— 1080 Γ— 4 = 8,294,400 bytes
         β‰ˆ 8 MB per full-screen layer!

  ─────────────────────────────────────────────────────────────

  ⚠️ LAYER EXPLOSION - Common Problem:

  Problematic code:
  /* Every list item gets its own layer! */
  .list-item {
    will-change: transform;  /* Creates layer! */
  }

  If you have 1000 list items = 1000 layers!
  = Huge GPU memory usage
  = Slow compositing
  = Possible crashes on mobile!

  ─────────────────────────────────────────────────────────────

  βœ… Better approach:

  /* Only promote when needed */
  .list-item:hover {
    will-change: transform;  /* Layer only on hover! */
  }
  .list-item.animating {
    will-change: transform;  /* Layer only during animation! */
  }
⚠️ will-change Best Practices

DO: Apply will-change before animation starts, remove after animation ends.
DON'T: Apply will-change to everything or keep it permanently on static elements.

element.addEventListener('transitionend', () => element.style.willChange = 'auto');

The Compositing Process

COMPOSITING STEP BY STEP
  STEP 1: Collect Layer Information
  ───────────────────────────────────
  For each layer, compositor knows:
  β€’ texture: GPU_TEXTURE_ID     // Reference to painted bitmap
  β€’ position: { x: 100, y: 50 } // Screen position
  β€’ transform: matrix3d(...)    // Any transforms applied
  β€’ opacity: 0.9                // Transparency
  β€’ zIndex: 3                   // Stacking order

  STEP 2: Sort Layers by Z-Order
  ─────────────────────────────────
  1. Background layer (z: 0)
  2. Content layer (z: 1)
  3. Fixed header (z: 100)
  4. Modal overlay (z: 1000)
  5. Tooltip (z: 9999)

  STEP 3: Draw Layers (Back to Front)
  ─────────────────────────────────────
  GPU Framebuffer:

  Start: Empty
  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
  β”‚                         (empty)                             β”‚
  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

  Draw Layer 1 (background):
  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
  β”‚ β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘ β”‚
  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

  Draw Layer 2 (content) - blended on top:
  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
  β”‚ β–‘β–‘β–‘β–‘β–‘β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–‘β–‘β–‘β–‘β–‘β–‘β–‘ β”‚
  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

  Draw Layer 3 (header) with transform:
  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
  β”‚ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ”‚
  β”‚ β–‘β–‘β–‘β–‘β–‘β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–“β–‘β–‘β–‘β–‘β–‘β–‘β–‘ β”‚
  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

  Final: Complete frame ready for display!

  STEP 4: Display (Swap Buffers)
  ─────────────────────────────────
  GPU uses double/triple buffering - swap to display at vsync

The Complete Rendering Pipeline

Now let's see how ALL the pieces fit together β€” from the user typing a URL to pixels appearing on screen!

THE COMPLETE JOURNEY: URL β†’ PIXELS
  USER TYPES: https://example.com

  ═══════════════════════════════════════════════════════════════
  PHASE 1: NETWORK
  ═══════════════════════════════════════════════════════════════

  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”     β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”     β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
  β”‚   DNS        │────▢│    TCP       │────▢│    TLS       β”‚
  β”‚   Lookup     β”‚     β”‚   Handshake  β”‚     β”‚   Handshake  β”‚
  β”‚   (~20-120ms)β”‚     β”‚   (~40ms)    β”‚     β”‚   (~40-100ms)β”‚
  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜     β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜     β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
         β”‚                                          β”‚
         β–Ό                                          β–Ό
   "What's the IP?"                          "Connection secure!"
                                                    β”‚
                                                    β–Ό
                              β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                              β”‚     HTTP Request/Response      β”‚
                              β”‚     "GET /index.html"          β”‚
                              β”‚     ───────▢                   β”‚
                              β”‚     ◀─────── HTML bytes        β”‚
                              β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

  ═══════════════════════════════════════════════════════════════
  PHASE 2: PARSING (Parallel Processes)
  ═══════════════════════════════════════════════════════════════

  HTML Stream arrives:

  <html><head><link href="style.css"><script src="app.js">...

                              β”‚
        β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
        β”‚                     β”‚                     β”‚
        β–Ό                     β–Ό                     β–Ό
  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”     β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”     β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
  β”‚ HTML Parser  β”‚     β”‚ CSS Parser   β”‚     β”‚ Preload      β”‚
  β”‚              β”‚     β”‚              β”‚     β”‚ Scanner      β”‚
  β”‚ Tokenize     β”‚     β”‚ Parse CSS    β”‚     β”‚              β”‚
  β”‚ Build DOM    β”‚     β”‚ Build CSSOM  β”‚     β”‚ Find more    β”‚
  β”‚              β”‚     β”‚              β”‚     β”‚ resources!   β”‚
  β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜     β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜     β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜
         β”‚                    β”‚                     β”‚
         β–Ό                    β–Ό                     β–Ό
  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”     β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”     β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
  β”‚              β”‚     β”‚              β”‚     β”‚ Fetch:       β”‚
  β”‚  DOM TREE    β”‚     β”‚   CSSOM      β”‚     β”‚ - images     β”‚
  β”‚              β”‚     β”‚              β”‚     β”‚ - scripts    β”‚
  β”‚ document     β”‚     β”‚ StyleSheets  β”‚     β”‚ - fonts      β”‚
  β”‚  └─html      β”‚     β”‚  └─rules     β”‚     β”‚ (parallel!)  β”‚
  β”‚    └─body    β”‚     β”‚    └─styles  β”‚     β”‚              β”‚
  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜     β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜     β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
         β”‚                    β”‚
         β”‚    BLOCKED BY:     β”‚
         β”‚    ◀──────────────│ CSS (render blocking)
         β”‚    <script> (parser blocking)
         β”‚                    β”‚
         β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                   β”‚
                   β–Ό
         Wait for BOTH to be ready...

  ═══════════════════════════════════════════════════════════════
  PHASE 3: RENDER TREE CONSTRUCTION
  ═══════════════════════════════════════════════════════════════

     β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”         β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
     β”‚   DOM TREE   β”‚    +    β”‚    CSSOM     β”‚
     β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜         β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜
            β”‚                        β”‚
            β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                       β”‚
                       β–Ό
            β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
            β”‚   STYLE CALC       β”‚
            β”‚                    β”‚
            β”‚ For each DOM node: β”‚
            β”‚ - Find matching    β”‚
            β”‚   CSS rules        β”‚
            β”‚ - Apply cascade    β”‚
            β”‚ - Resolve inherit  β”‚
            β”‚ - Compute values   β”‚
            β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                      β”‚
                      β–Ό
            β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
            β”‚   RENDER TREE       β”‚
            β”‚                    β”‚
            β”‚ Only VISIBLE nodes β”‚
            β”‚ + computed styles  β”‚
            β”‚                    β”‚
            β”‚ (display:none      β”‚
            β”‚  elements removed) β”‚
            β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                      β”‚
                      β–Ό

  ═══════════════════════════════════════════════════════════════
  PHASE 4: LAYOUT
  ═══════════════════════════════════════════════════════════════

            β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
            β”‚      LAYOUT        β”‚
            β”‚     (Reflow)       β”‚
            β”‚                    β”‚
            β”‚ Calculate:         β”‚
            β”‚ β€’ Exact positions  β”‚
            β”‚ β€’ Exact sizes      β”‚
            β”‚                    β”‚
            β”‚ Convert:           β”‚
            β”‚ %, em, vh β†’ pixels β”‚
            β”‚ auto β†’ calculated  β”‚
            β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                      β”‚
                      β–Ό
            β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
            β”‚  LAYOUT TREE       β”‚
            β”‚                    β”‚
            β”‚ Each node has:     β”‚
            β”‚  x: 100            β”‚
            β”‚  y: 50             β”‚
            β”‚  width: 400        β”‚
            β”‚  height: 200       β”‚
            β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                      β”‚
                      β–Ό

  ═══════════════════════════════════════════════════════════════
  PHASE 5: PAINT
  ═══════════════════════════════════════════════════════════════

            β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
            β”‚       PAINT        β”‚
            β”‚                    β”‚
            β”‚ Generate drawing   β”‚
            β”‚ commands:          β”‚
            β”‚ β€’ DrawRect(...)    β”‚
            β”‚ β€’ DrawText(...)    β”‚
            β”‚ β€’ DrawImage(...)   β”‚
            β”‚                    β”‚
            β”‚ Create paint       β”‚
            β”‚ layers for:        β”‚
            β”‚ β€’ transform        β”‚
            β”‚ β€’ opacity          β”‚
            β”‚ β€’ position:fixed   β”‚
            β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                      β”‚
                      β–Ό
            β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
            β”‚   PAINT RECORDS    β”‚
            β”‚   per layer        β”‚
            β”‚                    β”‚
            β”‚ Layer 1: [...]     β”‚
            β”‚ Layer 2: [...]     β”‚
            β”‚ Layer 3: [...]     β”‚
            β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                      β”‚
                      β–Ό

  ═══════════════════════════════════════════════════════════════
  PHASE 6: RASTERIZATION
  ═══════════════════════════════════════════════════════════════

            β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
            β”‚   RASTERIZATION    β”‚
            β”‚                    β”‚
            β”‚ Convert paint      β”‚
            β”‚ records to pixels  β”‚
            β”‚ (bitmaps/textures) β”‚
            β”‚                    β”‚
            β”‚ Done on GPU or     β”‚
            β”‚ raster threads     β”‚
            β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                      β”‚
                      β–Ό
            β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
            β”‚   LAYER TEXTURES   β”‚
            β”‚   in GPU memory    β”‚
            β”‚                    β”‚
            β”‚ [β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ] β”‚
            β”‚ [β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ] β”‚
            β”‚ [β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ] β”‚
            β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                      β”‚
                      β–Ό

  ═══════════════════════════════════════════════════════════════
  PHASE 7: COMPOSITING
  ═══════════════════════════════════════════════════════════════

            β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
            β”‚    COMPOSITOR      β”‚
            β”‚  (Separate Thread) β”‚
            β”‚                    β”‚
            β”‚ Combine layers:    β”‚
            β”‚ β€’ Apply transforms β”‚
            β”‚ β€’ Apply opacity    β”‚
            β”‚ β€’ Handle z-order   β”‚
            β”‚ β€’ Blend together   β”‚
            β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                      β”‚
                      β–Ό
            β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
            β”‚    FINAL FRAME     β”‚
            β”‚   sent to GPU      β”‚
            β”‚                    β”‚
            β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
            β”‚ β”‚β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ”‚ β”‚
            β”‚ β”‚β–ˆβ–ˆ YOUR PAGE β–ˆβ–ˆβ–ˆβ”‚ β”‚
            β”‚ β”‚β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ”‚ β”‚
            β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
            β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                      β”‚
                      β–Ό
            β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
            β”‚   DISPLAY!        β”‚
            β”‚   (60fps = 16.6ms  β”‚
            β”‚    per frame)      β”‚
            β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
TIMELINE VIEW: WHAT HAPPENS WHEN?
  Time ──────────────────────────────────────────────────────────────▢

  NETWORK:
  β”‚ DNS β”‚ TCP β”‚ TLS │════════ HTML Download ═════════│
  β”‚     β”‚     β”‚     β”‚     │══ CSS ══│               β”‚
  β”‚     β”‚     β”‚     β”‚     │═══════════ JS ══════════│
  β”‚     β”‚     β”‚     β”‚     │══════ Images ═══════════════════════════│

  MAIN THREAD:
  β”‚           β”‚ HTML Parse β”‚ Style β”‚ Layout β”‚ Paint β”‚     β”‚
  β”‚           │────────────│───────│────────│───────│     β”‚
  β”‚           β”‚   DOM      β”‚       β”‚        β”‚       β”‚     β”‚
  β”‚           β”‚ ◀─blocked─▢│       β”‚        β”‚       β”‚     β”‚
  β”‚           β”‚ (by JS/CSS)β”‚       β”‚        β”‚       β”‚     β”‚

  COMPOSITOR THREAD:
  β”‚                                         β”‚ Composite │────────▢
  β”‚                                         │───────────│
  β”‚                                         β”‚           β”‚

  KEY METRICS:
  β”‚                                                              β”‚
  β”œβ”€β”€ TTFB (Time to First Byte)                                β”‚
  β”‚                                                              β”‚
  β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ FCP (First Contentful Paint)                      β”‚
  β”‚                                                              β”‚
  β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ LCP (Largest Contentful Paint)         β”‚
  β”‚                                                              β”‚

  BLOCKING POINTS:
  β€’ CSS blocks rendering (render-blocking)
  β€’ <script> blocks parsing (parser-blocking)
  β€’ JavaScript on main thread blocks everything else!
RE-RENDERING: WHAT TRIGGERS WHAT?
  When you change something, what work does the browser do?

  ═══════════════════════════════════════════════════════════════
  CHANGE WIDTH/HEIGHT/MARGIN (Geometry Changes)
  ═══════════════════════════════════════════════════════════════

  [Style] β†’ [Layout] β†’ [Paint] β†’ [Composite]
             ↑
    Most expensive! Recalculates positions for potentially
    many elements. Avoid in animations!

  ═══════════════════════════════════════════════════════════════
  CHANGE COLOR/BACKGROUND/SHADOW (Visual-only Changes)
  ═══════════════════════════════════════════════════════════════

  [Style] β†’         β†’ [Paint] β†’ [Composite]
                       ↑
    Medium cost. Skips layout but still repaints affected area.

  ═══════════════════════════════════════════════════════════════
  CHANGE TRANSFORM/OPACITY (Compositor-only Changes)
  ═══════════════════════════════════════════════════════════════

  [Style] β†’         β†’         β†’ [Composite]
                                   ↑
    Cheapest! GPU just moves/blends existing textures.
    Can run at 60fps even with heavy JavaScript!

  ═══════════════════════════════════════════════════════════════

  VISUAL COMPARISON:

  .move-with-left {                .move-with-transform {
    left: 100px;  // BAD!            transform: translateX(100px); // GOOD!
  }                                }

  Left animation:                  Transform animation:
  β”Œβ”€β”€β”€β”€β”¬β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”       β”Œβ”€β”€β”€β”€β”¬β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”
  β”‚ L  β”‚ P  β”‚ C  β”‚ L  β”‚ P  β”‚       β”‚ C  β”‚ C  β”‚ C  β”‚ C  β”‚ C  β”‚
  β””β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”˜       β””β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”˜
  Layout every frame!              Composite only! Much faster!

Frame Budget

⏱️ The 16.6ms Budget

For smooth 60fps animations, each frame must complete in 16.6ms (1000ms Γ· 60 frames).

Frame breakdown:
β€’ JavaScript: ~10ms max
β€’ Style + Layout + Paint + Composite: ~6ms

If any frame takes longer, you get "jank" (visible stutter)!

Optimization Best Practices

1
Animate transform/opacity
These are compositor-only properties. They skip layout and paint entirely!
2
Avoid layout thrashing
Batch DOM reads together, then batch writes. Never interleave read-write-read-write.
3
Inline critical CSS
Inline above-the-fold CSS to avoid render-blocking. Load rest async.
4
Use async/defer scripts
Don't block the HTML parser. Use defer for scripts that need DOM.
5
Don't over-use layers
Each layer costs memory. Only promote elements that actually animate.
6
Use passive listeners
For scroll/touch events, use {passive: true} to keep scrolling smooth.

Animation: Right vs Wrong

❌ Wrong: Animating left
.box {
  position: absolute;
  left: 0;
  transition: left 0.3s;
}
.box:hover {
  left: 100px; /* Triggers layout! */
}
βœ… Right: Animating transform
.box {
  transform: translateX(0);
  transition: transform 0.3s;
}
.box:hover {
  transform: translateX(100px);
  /* Compositor only! */
}

Summary

🎯 The Complete Pipeline

HTML β†’ DOM β†’ CSSOM β†’ Render Tree β†’ Layout β†’ Paint β†’ Composite β†’ Screen

Change width:     [Style] β†’ [Layout] β†’ [Paint] β†’ [Composite]
Change color:     [Style] β†’         β†’ [Paint] β†’ [Composite]
Change transform: [Style] β†’         β†’         β†’ [Composite]

Less work = Faster! Transform/opacity skip the most steps!

Key Takeaways

Stage What to Optimize Key Techniques
Network Reduce latency Preconnect, HTTP/2, CDN
Parsing Don't block parser async/defer scripts, inline critical CSS
Styles Reduce complexity Simple selectors, avoid *
Layout Avoid thrashing Batch reads/writes, use transform
Paint Reduce area/complexity Promote layers, avoid shadows
Composite Use GPU transform, opacity only
πŸŽ‰ Congratulations!

You now understand the complete browser rendering pipeline β€” from DNS resolution to compositing. Use this knowledge to build faster, more performant web applications!