Browser render cycle and Chrome developer tools

A summary of how to measure each step of browser render cycle using Chrome dev tools and a few possible optimisations.

Sonika Malloth
Sonikblasts
7 min readSep 7, 2016

--

Writer’s note 1: This article is a summary of 2 beginner level courses I’ve taken with Udacity on web optimisations. They explain the nitty-gritty of how a browser renders content on screen and how Chrome developer tools can be used to measure the performance at every stage of the render cycle. The full courses are Website performance optimisation and Browser rendering optimisation to be taken in the mentioned order and are highly recommended for front-end engineers, especially the once that are aiming to create highly smooth animations.

[Definition] Critical Rendering Path (CRP): Sequence of steps browser goes through to convert HTML, CSS and JS into actual pixels on the screen. Simply put if this is optimised, the web pages run faster.

In interest of space “optimisation” is shortened to “op” throughout the article

Critical Rendering Path

[Stage 1] DOM: As soon as the browser receives data from server its tokeniser starts parsing the HTML creating Document Object Model.

[op 1]Send partial HTML to start building webpage while more data is being fetched in background.

[Stage 2] CSSOM: Browser builds CSS Object Model from inline CSS or server fetched files. As CSS rules cascade down to child elements the browser needs to wait till the entire CSSOM is built making CSS render blocking.

[op 1]Add inline CSS to remove fetch request RTT. But it will work only for small set of rules as a huge set will make the HTML file heavier and browser anyways waits for all CSS to be fetched before rendering even if you divide it across files!

[op 2]Add media queries to tell browser exactly what all CSS is required to render that page. Media queries can be screen size specific or orientation specific or mode (view/print etc) specific.

[Stage 1–2] JS: Javascript can create new DOM elements or change styles of existing ones. Hence based on the JS code the parser might loop through stages 1 & 2 multiple times.

[op 1]External JS is parser blocking. Inline JS doesn’t block DOM construction. But inline JS can lead to redundant code on multiple pages.

[op 2]Adding async attribute on script tag makes that JS file non-blocking.

Measure before you act! [Part 1]

Cardinal rule of web performance — measure first and then optimise

There is no one golden rule when it comes to web app optimisations. Minimising, compressing and caching the files always help but it is highly dependent on how your project is structured. The key is to deliver as less bytes as possible, reducing the critical resources (which can be parser or render blocking) and reduce the CRP length (number of round trips made to get all critical resources). These are called CRP metrics. Please read this great article(5-min read) written by Jesca on how to use Chrome developer tools(network tab) to identify/measure the above metrics with examples.

Writer’s note 2: A CRP loop can be optimised at 2 levels, before rendering and while rendering. The above mentioned 3 stages occur before rendering which create the blue-print of the page and the next 3 stages convert the blue-print to actual pixels on screen.

[Stage 3] Render Tree: Render Tree captures only the visible content. It combines the DOM and CSSOM and gets the actual representation of what we will see on the screen.

[op 1]Hide the elements that are not visible in a particular frame with CSS property of display set to none instead of setting property opacity to zero.

[op 2]Remove all unnecessary DOM elements whenever possible.

[Stage 4] Layout: Layout stage figures out where and how the elements are positioned on the screen.

[op 1]Layout runs on the entire render tree to figure out all relative positions. So keep the render tree as small as possible.

[Stage 5] Paint: Paint stage is where the browser draws the pixels. It divides the entire page into layers so as to minimise the paint area on updates.

[op 1]Though we can’t control layer creation, we can specify will-change CSS property on elements to tell Chrome/Firefox that these elements are bound to change frequently so they can make better decisions while layering.

Writer’s note 3: Optimisations discussed till now will help you achieve fast static webpages which involve very few CRP loops. When a web app involves animations, study says that 60FPS is a good target to provide jitter-free experience. So browser has 1000/60=16ms approx. to draw each frame!

Measure before you act! [Part 2]

Cardinal rule of web performance — measure first and then optimise

[Definition] Render Loop: A sequence of steps browser goes through while rendering an animation frame. It involves 1 or more CRP loops as required.

Render loop

Execute animation frame runs the JS needed to add new DOM elements or update existing ones to reflect the next animation step. The browser updates the DOM and CSSOM accordingly and creates render tree in recalculate styles. Then layout step calculates the layouts and updates the layer tree. Paint of actual pixels on various layers happens and finally composite layer step manages layers on screen.

Measure…

The timeline tab of Chrome developer tools gives a clear picture of each step of every render loop in a flame chart view. Hit the record button on top left corner of timeline tab and refresh page to record a timeline trace.

Writer’s note 4: You can save/load any timeline trace to browser for analysis from right-click menu of timeline tab! I shall continue explaining with a timeline trace of a 2D animation(Blocks) from one of my sample projects.

Render loop of a frame that took 41.2ms

The top window shows the CPU usage and frame rate of each frame indicating the ones closer to 60FPS in greens and the longer frame in reds. That gives an overall timeline of animation. The bottom window is a flame chart view of sequence of steps in a single render loop. Here I selected a long frame near the point of 6914ms from the above timeline.

Detailed view of render loop

Clicking on the frame opens another window at the bottom that has various tabs. While flame chart view gives you an overall picture, the event log gives you the exact time taken by each step. In case of JS steps you can open to see what functions were executed for how much time. Expansion of recalculate style steps will show the fetch requests for media resources sent during rendering (if any).

The paint will open a small preview on right-bottom corner of what was painted in that step. The paint profiler link will take you to a detailed event log of every draw that has occurred during that paint step. Another tab of interest is Layers. It gives you a 3D view of all layers that have been painted in the particular frame.

Optimise…

  • Once you understand the JS bottlenecks from event log, you can use web workers to have only JS required for rendering on parser blocking thread.
  • Use requestAnimationFrame to run the function needed to animate instead of setTimeout or setInterval. It lets browser choose the right time to run the next animation loop when the render pipeline isn’t heavy.
  • Some steps are skipped by browser based on what properties have been updated in the render tree. For example, update of geometry related CSS properties like width, position triggers the layout step. If properties like background colour, opacity is updated layout isn’t run. The transform property skips both layout and paint steps. Csstriggers gives a comprehensive list of what steps are triggered by each property change.
  • Avoid forced synchronous layout. Consider the following code:

When you access offsetWidth of an element in JS, the browser has to calculate layouts to get it. And when you make a style change the layout is called again. So in above code every for loop is costing 2 layouts! This will increase the render loop length dropping the frame rate. Any property for which the browser has to run layout like geometric properties can cause FSL.

Writer’s note 5: There is no one way to optimise a web app. It highly depends on your project. Measure first to find your bottlenecks and optimise accordingly.

--

--

Sonika Malloth
Sonikblasts

Web full stack developer — freelancer / Trinity Grade 8drummer / amateur poetess. www.sonikblasts.com own publication at @Sonikblasts