Critical Rendering Path for the Browser

Image of Author
March 28, 2022 (last updated April 28, 2023)

The browser CRP, or Critical Rendering Path, is the fundamental sequence of steps required to get the "glorified text files" of HTML, CSS, and JS, from lines of text in a file, to pixels in a browser.

  1. A HTTP request-response cycle results in a HTTP response body containing a HTML string.

  2. Parse the HTML and use it to generate the DOM (Document Object Model) in the browser. This is an incremental process that can involve additional requests for additional payloads that affect the construction of the DOM. For example, additional CSS and JS files can be requested, and the JS file could itself manipulate the DOM.

  3. Further parsing of the HTML, this time focused on CSS and generating the CSSOM in the browser

  4. Processing the DOM and CSSOM to determine what is to be rendered, thereby generating the "render tree".

  5. Use the "render tree" of what ought to be rendered, and process it to calculate what the layout of the page ought to be, accounting for z-index layering, entity widths and heights and colors, etc. This is the "layout tree".

  6. Turning the "layout tree" into "painted pixels" in the browser. I'm unaware of a name for this step.

JavaScript is incidental

The fact that JavaScript is incidental is seen by the fact that the above steps make almost no reference to it. HTML and CSS are all that is needed to render a page. So JavaScript is the least important in this regard. But, it's simultaneously the most important of all three because with it you can manipulate, create, and destroy everything else. But, it didn't have to be JavaScript, it could've been any other language.

In a world without JavaScript, the DOM would still be generated in order to figure out what gets rendered. On top of this, browsers would still give you an API to interface with the DOM, which allows developers to manipulate the DOM, it just would be in some other language. The browsers don't just define an interface for the DOM, they provide you an implementation of the interface in JavaScript, which you have access to on the browser, client-side. You can basically think of the DOM API provided by browsers as a package you would otherwise install via npm on nodejs on the server. You could then import window from 'dom-api' to get access to it. Of course, this is not the case, you just get access to it when client-side javascript runs. But, the point is, the browser bundles together a lot of complex, feature-rich APIs that let you do much more than JavaScript alone could.

Another way to clarify the difference between JavaScript and the DOM is to imagine if browsers all chose to switch to python as their client-side scripting language of choice. Then, your <script> tags would all have python code in them. Browsers would then implement DOM APIs in python and provide them to you by default when they executed your python scripts. You would be able to create div elements, and add text to them, all with python code.

What I'm trying to say is that the DOM is controlled by the browser, and the browser lets you interface with the DOM in whatever way they choose. JavaScript is what they chose.

Here's a hypothetical. I wave a magic wand and have multiple languages supported as scripting languages in the browser. Fundamentally this means a subset of "secure" standard library functions, and an extension to support the DOM APIs. Your entry point text file could then declare it's scripting env. This could be like .sh files on the OS do it, so instead of #!/usr/bin/env python you could write #! /languages/python (browsers would implement whatever is in this pseudo-location). Alternatively, you could add an attribute to a script tag.

<script lang="python" src="main.py"></script>

Imagine the following, and you can replace python with any other language (supported by the browser).

<html>
  <body>
    <div id="root"></div>
    <script lang="python" src="main.py"></script>
  </body>
</html>
# main.py

import dom

root = dom.document.getElementById('root')
child = dom.document.createElement('p')
child.innerText('hello')
root.appendElement(child)

DOM APIs

You can directly access the DOMParser API and the DOMImplementation API to do things like create a document from scratch in JavaScript or turn an HTML string into a DOM

Resources