Part 3: Inside the modern web browser

A rendering processor’s inner workings

This is part 3 in 4 blog series that examines browsers. In previous posts, we have covered multiprocess Architecture and Navigation flow. Today we will look inside the renderer process.

Web performance is affected in many ways by renderer. There is much happening in the renderer process. This is not a comprehensive overview. Web Fundamentals offers many other resources if you want to dig into the rendering process.

Renderer processes handle web contents

All that happens within a tab are handled by the renderer. Most of the code that you send to the end user is handled by the main thread in a renderer. Worker threads may handle some of the JavaScript if you use either a web worker (or a service worker). A renderer runs raster, and compositor threads to efficiently render a page.

The rendering process is responsible for transforming HTML, CSS, JavaScript, and JavaScript into pages the user can use.

Figure 1. Renderer process using main thread, worker threads and a compositor thread.


Construction of an DOM

After the renderer process gets a notification for a navigation, and begins to receive HTML data from it, the main thread will begin to read the text string and convert it to a Document Object odel.

The DOM, which is a browser’s internal representation for a page, also includes the data structure (and API) that JavaScript allows web developers to interact with.

The HTML Standard defines the process of parsing HTML into a document. As you may have observed, HTML feeds to browsers never fail to throw an error. The tag's closing is valid HTML. Hi! I’m ! is treated like you wrote “Hi!” Chrome .. Because the HTML specification has been designed to deal with these types of errors smoothly, This section of the HTML specification explains how it works.

Subresource loading

Images, CSS, JavaScript, and CSS are all common resources for websites. These files should be available from the internet or in cache. Although the main thread can request those files individually as they locate them during parsing to construct a DOM (which could happen), “preload scanner”, which runs concurrently, is faster. Preload scanner checks for tokens created by HTML parser in the HTML document and makes requests to it.

Figure 2: The main thread parsing HTML and building a DOM tree

JavaScript blocks parsing

When an HTML parser discovers a script> element, it suspends parsing the HTML document. The JavaScript code must be loaded, parsed, and executed by the HTML parser. Why is this? JavaScript allows you to modify the structure of the document with .write(). The overview of parsing model can be found in the HTML spec. It has a beautiful diagram. JavaScript needs to be running before the HTML parser is able to resume the parsing. is a blog that explains JavaScript execution.

Navigate to the website where you would like to download resources

Developers can use many methods to communicate hints with the browser to load properly. Add the defer or async attributes to the script> tag, if your JavaScript does NOT use document.write(). JavaScript code is then loaded by the browser asynchronously. The browser does not stop parsing. You can also use JavaScript code, if you feel it is appropriate. link rel="preload tells browser the resource is needed to perform current navigation. Resource prioritization – How to Get the Browser Helping You.

Style calculation

The DOM doesn’t tell you how the page should look. However, we can use CSS to design page elements. This thread interprets CSS and calculates the computed style of each DOM element. This section contains information on the style applied to each element, based upon CSS selectors. DevTools has this section.

Figure 3: The main thread parsing CSS to add computed style

You can provide CSS for each DOM element even though you don’t have to. tag displays larger than HTML2>_ tag. Margins are specified for every element. It is due to the browser’s default style sheet. provides a detailed description of Chrome’s default CSS. You can also see the source code.


While the renderer can now understand the structure of a document, as well as the styles used for each node, this isn’t enough information to be able to render a page. As if you were trying to describe the painting to a friend via phone. You can’t tell your friend what the actual painting might look like by simply saying “There’s an enormous red circle” and “There’s also a small blue rectangle.”

Figure 4: A person standing in front of a painting, phone line connected to the other person

The layout process is used to determine the elements’ geometrical arrangement. The layout tree is created by the main thread. It includes computed styles as well as the DOM. While layout tree is similar in structure to the DOM trees, it does not contain information beyond what is displayed on the page. If Display: None is used, this element does not belong in the layout hierarchy. But, an element with Visibility: Hidden is included in it. Similarly, if a pseudo class with content like p::before{content:”Hi! ” is applied, it is included in the layout tree even though that is not in the DOM.|”} can be applied to the layout tree, even though it’s not part of the DOM.|”} may be used, but it will still be included in the layout trees even though they are not in the DOM.|”} will be applied. It is added to the layout tree even if it isn’t in the DOM.}

Figure 5: The main thread going over DOM tree with computed styles and producing layout tree

Figure 6: The box layout of a paragraph that moves due to line breaks

A difficult task is to decide the page layout. A simple page layout such as a block-flow from top of bottom to base must consider the size and position of fonts. These affect the dimensions and shapes and location of paragraphs.

CSS can change direction of writing, alter the position of elements, or make them float to one end. It is not difficult to see that this stage of the layout process can be quite challenging. Chrome has a large engineering team working on the layout. Several talks recorded at the BlinkOn Conference provide details and are worth a look.


Figure 7: A person in front of a canvas holding paintbrush, wondering if they should draw a circle first or square first

Even though you have the DOM and style to make a page, it is still insufficient. You are trying reproduce a painting. Even though you are familiar with the sizes, shapes and locations of various elements, you need to decide in which order they should be painted.

Z-index , for example, might be assigned to certain elements. However, incorrect rendering of will result if the HTML is painted in the wrong order.

Figure 8: Page elements appearing in order of an HTML markup, resulting in wrong rendered image because z-index was not taken into account

In this step of painting, the main thread traverses the layout tree in order to make paint records. Notes about painting processes like “background, text, rectangle” and so on are called paint records. The following process is likely to be familiar if you are familiar with JavaScript and canvas> elements.

Figure 9: The main thread walking through layout tree and producing paint records

Maintaining a rendering pipeline update is expensive

Figure 10: Order generated by DOM+Style, Layout and Paint Trees

What is most important in the rendering pipeline is the fact that every operation creates new data. To illustrate, the Paint order should be reset for all areas that have been affected by a layout change.

When animating elements the browser needs to execute these operations between each frame. Our screens refresh 60 frames per second, which is 60 fps. Animation will look seamless to the human eye when things are moved across the screen at the same frame. Animations that miss frames will cause the page to appear “janky”.

Figure 11: Animation frames on a timeline

Even if rendering is on-time, this calculation runs on the main Thread, meaning it can be blocked if JavaScript has been running.

Figure 12: Animation frames on a timeline, but one frame is blocked by JavaScript

You can divide JavaScript operation into small chunks and schedule to run at every frame using requestAnimationFrame(). Optimize JavaScript Execution will provide more detail on the topic. Web Workers might allow you to run your JavaScript without blocking the main thread.

Figure 13: Smaller chunks of JavaScript running on a timeline with animation frame


Which method would you use to draw a page

Figure 14 Animation of the Naive Rastering Process

What does the browser do with the information it has about the layout of the document and how each element is styled? The process of turning this information into pixels is known as “rasterizing.”

A naive approach to this problem is to raster portions within the viewport. A user could scroll down to the page and move the rastered frames, filling in the spaces by rastering further. Chrome did rasterizing in the same way when it first came out. But, modern Chrome uses a sophisticated process called “compositing”.

Compositing: What’s it all about?

Figure 15: Animation of the composite process

It is the process of creating a composite page by dividing it into layers. Scroll happens because layers are already pre-rasterized. All it needs to do to make a new frame is create one. It is possible to make animation the same way as moving layers.

DevTools Panel can show you how your website is broken down into layers.

Dividing into layers

For the purpose of determining which elements are needed to be within which layers, the main thread traverses the layout tree in order to make the layer tree. The part called “Update Layer Tree” is found in DevTools’ performance panel. If you feel that certain sections of a page need to be in a different layer (like the slide-in menu), then you can tell browsers by using attribute.

Figure 16: The main thread walking through layout tree producing layer tree

The temptation to put layers on every element might make it seem easier. However, this could lead to slower rendering than simply rasterizing small sections of a page each frame. For more details, refer to Keep Compositor Only Properties and Manage LayerCount.

A composite of the main thread and its stere

When the layer tree has been constructed and orders for paint have been established, the main thread transfers that information to a compositor. Each layer is then rasterized using the compositor. If a layer is large, such as the page’s length, then the compositor will divide it into tiles before sending each tile off for rastering. These threads are responsible for rasterizing each tile, and storing them in GPU Memory.

Figure 17: Raster threads creating the bitmap of tiles and sending to GPU

Compositor threads have the ability to prioritise different raster threads, so items in the viewport (or near) can be set up first. You can also use multiple tilings on a layer to achieve different resolutions such as zoom-in.

The compositor thread looks at the tiles and gathers their information. This is draw Quads. It then creates a Compositor Frame.

Information such as where the tile is located in memory. Compositor frame A set of draw quads that represent a page’s frame.

A compositorframe is then submitted via IPC for the browser process. An additional compositor frame can then be sent to the browser via IPC. This compositor framework is sent to GPU to be displayed on screen. The compositor thread will create another compositorframe to display the scroll event.

Figure 18: Compositor thread creating compositing frame. Frame is sent to the browser process then to GPU

Compositing can be done with the main thread. It is possible to composite without waiting for JavaScript execution, style calculation, or JavaScript execution. For smooth performance is the best compositing animations. If the layout of paint or other elements needs to be adjusted, then it is necessary to include the main thread.

Get ready

Here we will be discussing rendering pipeline. This article will provide more information about optimizing website performance.

This series’ final two posts will focus on the compositor thread. We’ll also examine what happens when users input mouse click and mouse motion.

I hope you liked the post. Thank you for reading the post.

Next, Input is coming towards the compositor

Get feedback

rss_feed Subscribe RSS, to get the most up-to-date information right in your favorite reader.