Skip to content

From Receiving HTML to Drawing the Page

web | August 26, 2026


It is tempting to think that a page appears as soon as the browser receives HTML from the server. HTML, however, is not the screen itself. It is closer to a document that describes which elements exist and how they relate to one another.

The browser must turn that document into a structure it can work with and apply CSS to it. It then calculates the size and position of every element, determines what to draw and in which order, and combines multiple layers. Only after this work does the page we see appear on the screen.

This article continues where “From Typing naver.com to Receiving HTML” left off. We will follow the first byte of HTML across the browser's rendering pipeline until it becomes pixels on the screen.

The Browser Reads HTML While It Is Still Arriving

The browser does not wait for the entire HTML file to arrive. It begins reading from the start as soon as data comes in over the network. This is why a browser can display part of a long document before the download has finished.

We can simplify the transformation from HTML into a structure the browser understands as follows:

Bytes → Characters → Tokens → Nodes → DOM

The browser interprets the bytes as characters according to the response's encoding information. It then separates start tags, end tags, attributes, and text into tokens. The HTML parser processes those tokens one by one, creates nodes, and connects them into a tree.

Parsing can begin on the part of the document that has already arrived while the rest is still in transit. Resources discovered during parsing can also start downloading separately. Browsers overlap downloading, parsing, and preparation for rendering whenever possible.

HTML Becomes the DOM

Suppose the browser receives this HTML:

<body>
  <main>
    <h1>Today's News</h1>
    <p>Read the latest updates.</p>
  </main>
</body>

The browser does not keep these tags as plain strings. It constructs a DOM, or Document Object Model, that represents the relationships between the elements.

body
└── main
    ├── h1
    │   └── "Today's News"
    └── p
        └── "Read the latest updates."

In this DOM, body is the parent of main, while h1 and p are children of main. JavaScript can find an element with document.querySelector("h1") or insert a new node because the browser has converted the HTML into this object structure.

The HTML parser does not simply stop when it encounters invalid markup. It applies error-recovery rules defined by the HTML standard to repair structures such as missing end tags or incorrectly nested elements. As a result, the markup in the source file and the DOM shown in browser developer tools are not always identical.

The DOM represents the structure of the document, but it does not yet tell the browser each element's color, size, or position. That requires CSS.

What Happens When the Parser Finds Another Resource?

HTML also contains the addresses of resources the browser must fetch.

<link rel="stylesheet" href="/style.css" />
<script src="/app.js"></script>
<img src="/news.jpg" alt="Today's news" />

When the parser encounters elements such as link, script, and img, it starts requests for CSS, JavaScript, and images. These resources do not all interrupt HTML parsing in the same way. An image can generally begin downloading while parsing continues, whereas a classic script without additional attributes can pause the parser.

Browsers also use a preload scanner that looks ahead of the main HTML parser. Even if the main parser is paused by script execution, the scanner can discover resources that will soon be needed and request them in advance. This reduces time that would otherwise be spent waiting without useful network work in progress.

The browser cannot discover everything in advance. Some resources are inserted dynamically by JavaScript, while others—such as a CSS background-image—cannot be found until another file has been downloaded and parsed. The later a critical resource is discovered, the longer the first render may take.

CSS Becomes the CSSOM

CSS is not applied to the page as an unprocessed string. The browser parses it into the CSS Object Model, or CSSOM.

The browser considers its default user-agent styles together with the rules written by the page author. It determines which selectors match each element, then uses the cascade—including inheritance, specificity, and source order—to calculate the element's final styles.

Encountering an external stylesheet does not necessarily stop HTML parsing. The browser can continue constructing the DOM. A stylesheet that applies to the current screen is, however, render-blocking by default. If the browser painted before the CSSOM was ready and then immediately restyled everything, users could see a brief flash of unstyled content, commonly called FOUC.

CSS can also affect when JavaScript runs. JavaScript can read computed styles or measure an element's dimensions. If an earlier stylesheet is still loading, the browser may need to delay script execution so that those operations return accurate results.

Not every stylesheet needs to block the first render. A stylesheet with media="print", for example, is not required to draw the initial screen and therefore does not block the current screen's rendering. Distinguishing CSS required for the first view from CSS that can arrive later is an important part of web performance.

When Does JavaScript Stop HTML Parsing?

When the parser finds an external script without async, defer, or type="module", it pauses HTML parsing. It downloads and executes the file before continuing with the rest of the document.

This happens because JavaScript can read and alter the DOM. It can insert markup with document.write() or remove nodes that have already been created. To preserve the result implied by document order, the browser completes the script at the point where it appears.

Regular script : Pause parsing → Download → Execute → Resume parsing
async          : Download in parallel → Execute as soon as ready
defer          : Download in parallel → Execute in document order after parsing

An async script executes as soon as its download completes. HTML parsing may pause during execution, and the execution order of multiple async scripts is not guaranteed. This makes async suitable for independent code, such as some analytics scripts, that does not rely on other scripts or a complete DOM.

A defer script runs after HTML parsing and preserves document order. It works well for application code that needs the complete DOM or for scripts that depend on one another. A <script type="module"> also avoids blocking the parser and is deferred by default.

Parser blocking and render blocking are worth distinguishing. A regular classic script blocks the HTML parser by default. Long-running JavaScript can also occupy the main thread and delay what appears on screen, but identifying exactly what is blocked helps diagnose the problem more accurately.

The DOM and CSSOM Form the Render Tree

The browser combines the DOM's structure with the CSSOM's style information to create a structure used for drawing the page. This is commonly described as the Render Tree.

DOM + CSSOM → Render Tree

Not every DOM element appears in the Render Tree. Elements such as head, meta, and script have no visual representation. An element with display: none is excluded as well because it does not participate in layout. An element with visibility: hidden, on the other hand, remains part of layout and occupies space even though it is not visible.

The relationship also works in the other direction. Content created with ::before and ::after can appear on screen even though it is not a DOM node. The DOM is the document's semantic structure, while the Render Tree is a visual structure for rendering the page.

Actual browser engines may use different terminology and several intermediate structures. Here, Render Tree is a conceptual model for understanding the pipeline.

Layout: Calculating Size and Position

Knowing what to render is not enough; the browser still needs exact dimensions and coordinates. During Layout, it calculates the space each element occupies within the viewport.

The actual width of width: 80% depends on the parent element, while font-size: 2rem depends on the root font size. The browser considers parent-child constraints, the box model, line wrapping, and font information to resolve relative values into concrete sizes and positions.

A change to one element may affect many others. If a parent becomes narrower, text may wrap onto another line, increasing its height and moving every element below it. Recalculating positions and dimensions in an existing page is often called Reflow. Browser documentation and tools commonly use the term Layout, and the two terms are sometimes used interchangeably.

Layout can become expensive when JavaScript repeatedly writes a size and then immediately reads a position. To return an up-to-date value, the browser may be forced to perform Layout several times. This pattern is known as layout thrashing and is a common source of rendering performance problems.

Paint: Recording What to Draw and in What Order

After Layout establishes size and position, Paint determines how each element should be represented.

The browser examines visual properties such as backgrounds, borders, text, images, and shadows, and produces drawing commands. It does not rely on DOM order alone. It also considers stacking contexts and properties such as z-index to determine which content appears in front of other content.

Paint is best understood as recording what to draw and in what order. Turning those instructions into actual pixels is called rasterization. Rather than rebuilding the entire page as one large image every time, the browser can rasterize selected regions and layers.

Composite: Combining Layers into One Screen

The browser may separate parts of the page into compositing layers. After those layers are rasterized, the Composite stage places them in the correct position and order to produce the final screen. The GPU can assist with this work.

If an element already has its own compositing layer, changing its transform or opacity may require only moving that layer or changing its transparency. Layout and Paint can sometimes be avoided. This is why those two properties are often recommended for smooth animations.

Creating a separate layer for every element is not automatically faster. Every layer consumes memory and adds management and compositing work. Applying will-change broadly without evidence of a bottleneck can therefore make performance worse. It is safer to let the browser make layer decisions and provide hints only when measurement shows they are needed.

Does Every Change Repeat the Entire Pipeline?

Rendering continues after the first screen appears. JavaScript changes the DOM and styles, users scroll, and images or web fonts may arrive later.

The browser does not always repeat the complete pipeline. It can rerun only the stages required by the property that changed.

width change      → Layout → Paint → Composite
background change → Paint → Composite
transform change  → May be handled by Composite alone

A width change may alter the element's layout and the position of nearby content, so the browser must start at Layout. A background color does not change geometry and generally begins at Paint. A transform applied to a composited layer may be handled by Composite alone.

This table is a useful simplification, not an absolute rule. The actual work depends on the browser engine, element state, layer structure, and other CSS properties. It is more reliable to inspect real execution in a tool such as the Chrome DevTools Performance panel than to memorize a fixed cost for each property.

When Can We Say the First Screen Has Appeared?

DOMContentLoaded occurs after HTML parsing and the execution of deferred and module scripts. The load event waits for dependent resources such as images and stylesheets. Neither event necessarily matches the moment the user first sees content.

Several rendering metrics are closer to the user's experience:

  • FP, or First Paint, marks the first time anything—such as a background—is drawn.
  • FCP, or First Contentful Paint, marks the first appearance of content such as text or an image.
  • LCP, or Largest Contentful Paint, measures when a large element likely to represent the page's primary content is rendered within the viewport.

Even when HTML arrives quickly, late render-blocking CSS or JavaScript that occupies the main thread can delay FCP and LCP. Conversely, the browser can show some content as soon as the structure and styles required for the first view are ready, even if every resource has not finished downloading.

The network time discussed in the previous article and the rendering time discussed here are not separate user experiences. How quickly critical resources arrive and how quickly the browser processes them together determine the loading time a user perceives.

The Entire Process at a Glance

HTML received
→ Parse HTML
→ Build DOM
→ Parse CSS
→ Build CSSOM
→ Build Render Tree
→ Layout
→ Paint
→ Rasterize
→ Composite
→ Display on screen

This sequence is simplified for clarity. In a real browser, DOM construction, additional network requests, and preparation for rendering can overlap while HTML is still arriving. After the initial render, only the necessary parts of the pipeline may run again. Internal data structures and implementation details also vary between browser engines.

The important part is not memorizing the names of the stages. It is understanding what information each stage produces, what it must wait for, and which changes cause it to run again.

Closing

HTML is not a finished screen; it is the browser's starting point for constructing one. The browser converts HTML into the DOM and CSS into the CSSOM, then creates the visual structure required for rendering. It calculates dimensions and positions, turns drawing instructions into pixels, and combines layers into the result shown to the user.

Understanding this process makes a slow first render easier to investigate. We can ask whether HTML or CSS arrived late, whether JavaScript blocked the parser or occupied the main thread, or whether unnecessary Layout and Paint work was repeated.

Typing naver.com into the address bar does not end with retrieving HTML. The document must become structure, styles, coordinates, and pixels inside the browser before it becomes the web page we recognize.

References