Browser Internals

Browsers & Rendering

A browser turns HTML, CSS and JavaScript into pixels. Understanding parsing, the DOM, the critical rendering path and reflows makes performance work far less mysterious.

intermediate15 min readUpdated Sep 15, 2026
index.html
html
<!-- index.html -->
<link rel="preload" href="/fonts/inter.woff2"
      as="font" type="font/woff2" crossorigin />
<link rel="stylesheet" href="/styles.css" />
<script src="/app.js" defer></script>
Engines
Blink, Gecko, WebKit
Parsing
HTML to DOM
Styles
CSS to CSSOM
Layout
Geometry and position
Paint
Pixels to layers
Thread
Main thread runs JS

Why it matters

Why browser internals matter

A runtime, not a document

The browser is an execution environment with a DOM, APIs, storage, networking and a JavaScript engine.

The critical path

HTML, CSS and blocking JavaScript decide when the first pixels can appear.

Layout is expensive

Recalculating geometry forces the browser to redo work, which is why batching DOM changes matters.

The big picture

The three stages of rendering

Parse the markup, lay out the boxes, then paint and composite the pixels.

Parse

Build the tree

HTML becomes the DOM, CSS becomes the CSSOM, and together they form the render tree.

Layout

Place

The browser computes the size and position of every box.

Paint

Draw

Boxes are painted into layers and composited into the final frame.

Rendering at a glance

The core concepts

HTML parsing

The parser builds the DOM as it streams the document.

CSSOM

Stylesheets are parsed into a tree of rules and computed styles.

Render tree

Only visible elements with styles enter the render tree.

Layout

Also called reflow — computing the geometry of every box.

Paint and composite

Filling pixels and combining layers on the GPU.

The main thread

JavaScript, layout and paint share one thread, so long tasks stall everything.

A short history

From single engines to a shared platform

  1. 1993

    Mosaic

    The first widely used graphical browser brings images to the web.

    93
  2. 1995

    JavaScript

    Scripting turns static documents into applications.

    95
  3. 2008

    Chrome and V8

    A fast engine and multi-process architecture reset performance expectations.

    08
  4. 2013

    Blink

    Chrome forks WebKit, and Blink becomes the dominant engine.

    13
  5. Today

    A standards platform

    Engines converge on web standards, and browsers become the universal app runtime.

    Today

The complete guide

Browsers & Rendering: Everything you need to know

What does a browser actually do?

A browser is an execution environment, not just a document viewer. It parses HTML and CSS into trees, runs JavaScript, exposes APIs for networking and storage, and renders the result to pixels. Understanding that pipeline turns performance from guesswork into engineering.

The browser vendors ship three main engines: Blink (Chrome, Edge, Opera), Gecko (Firefox) and WebKit (Safari). They implement the same standards, so the concepts here apply everywhere even when the details differ.

Parsing HTML into the DOM

When the browser receives HTML, it parses it into the DOM: a tree of objects representing every element, attribute and piece of text. The parser is streaming, so it can start building the tree before the whole document arrives.

HTML parsing is resilient by design. A missing closing tag or a misplaced element does not stop the page; the parser recovers and keeps going. That is why malformed markup still renders, and why validating your HTML matters for predictability.

CSS and the CSSOM

Stylesheets are parsed into the CSSOM, a tree of rules. The browser then computes the final style of every element by combining the cascade, inheritance and specificity.

CSS is render-blocking: the browser will not paint until it has the styles it needs, because painting with the wrong styles would cause a visible flash. That is why a large stylesheet in the head delays the first paint, and why inlining critical CSS helps.

The render tree

The DOM and CSSOM combine into the render tree, which contains only the elements that will actually be displayed, each with its computed styles. Elements with display: none are excluded; visibility: hidden elements are included but not painted.

From here the browser knows what to draw, but not yet where.

Layout

Layout, also called reflow, computes the size and position of every box in the render tree. It walks the tree, resolving widths, heights, margins, padding and positioning, and produces a box model with exact geometry.

Layout is expensive because changes can cascade: resizing one element can move its siblings, its parent and everything below. Reading properties like offsetHeight forces the browser to ensure layout is up to date, so interleaving reads and writes triggers repeated layouts.

Paint and composite

After layout, the browser paints boxes into layers, filling in colours, text, images, borders and shadows. It then composites those layers, often on the GPU, to produce the final frame.

Some changes are cheaper than others:

  • Changing a colour triggers paint.
  • Changing a size triggers layout and paint.
  • Changing transform or opacity can be handled by the compositor, skipping layout and paint entirely.

That is why animations should stick to transforms and opacity. See the CSS Animations guide and the Web Performance guide.

The critical rendering path

The path from HTML to first pixels is:

  1. Parse HTML into the DOM.
  2. Parse CSS into the CSSOM.
  3. Combine them into the render tree.
  4. Layout the boxes.
  5. Paint and composite the frame.

Shortening this path is the core of perceived performance: fewer blocking resources, smaller CSS, and JavaScript that does not get in the way.

<!-- fast.html -->
<link rel="preload" href="/fonts/inter.woff2" as="font" type="font/woff2" crossorigin />
<style>/* critical, above-the-fold CSS */</style>
<script src="/app.js" defer></script>

preload starts important requests early, inlined critical CSS avoids a blocking round trip, and defer lets the parser finish before the script runs.

The main thread and JavaScript

The main thread runs JavaScript, layout, paint and event handling. Only one thing happens at a time, so a long task blocks input and makes the page feel frozen.

  • Keep tasks short and break up expensive work.
  • Move heavy computation to a Web Worker, which runs on a separate thread.
  • Avoid layout thrashing by batching DOM reads and writes.
  • Yield to the browser between chunks of work.

This is the same event loop you met in the JavaScript guide, now with rendering work competing for the same thread.

Storage and browser APIs

Beyond rendering, the browser provides storage and platform APIs: cookies, localStorage and sessionStorage, IndexedDB, the Cache API, service workers, WebSockets, WebRTC, the Clipboard, Notifications and more. These are what let a web page behave like an application. The PWA guide covers service workers and caching.

Best practices

  • Keep the critical path short: inline critical CSS, defer scripts.
  • Use preload for fonts and other render-critical assets.
  • Animate transform and opacity, not layout properties.
  • Batch DOM reads and writes to avoid layout thrashing.
  • Keep JavaScript tasks short; use Web Workers for heavy work.
  • Reserve space for images and embeds to avoid layout shift.
  • Test in multiple engines, especially Safari and mobile.

Common mistakes

  • Assuming the DOM is the HTML source.
  • Blocking rendering with large stylesheets or synchronous scripts.
  • Reading layout properties in a loop and forcing repeated reflows.
  • Animating width or top and causing jank.
  • Running heavy computation on the main thread.
  • Testing only in one browser and missing engine differences.

Where to go next

Browser internals explain why performance advice works. Put it into practice with the Web Performance guide, animate efficiently with CSS Animations, and manipulate the tree safely with DOM Manipulation. Then open DevTools and watch the rendering pipeline in the performance panel.

Loading scripts

A classic script in the head blocks parsing. defer downloads in parallel and runs after the document is parsed.

Prefer
<head>
  <link rel="stylesheet" href="/styles.css" />
  <script src="/app.js" defer></script>
</head>
Avoid
<head>
  <script src="/app.js"></script>
  <!-- parser blocks until
       it downloads and runs -->
</head>

Updating the DOM

Batch reads and writes. Interleaving them forces the browser to recalculate layout repeatedly.

Prefer
// read all, then write all
const height = el.offsetHeight;
const width = el.offsetWidth;

el.style.height = height + "px";
el.style.width = width + "px";
Avoid
// forces layout on every line
el.style.height = el.offsetHeight + "px";
el.style.width = el.offsetWidth + "px";

FAQ

Frequently asked questions

Keep learning

Related topics from the roadmap.

$ start learning

Ready to start learning Browsers & Rendering?

Our interactive tutorial walks you through Browsers & Rendering step by step — with quizzes and real code you can run in the browser.