SpeedCurve reports the number of critical blocking resources in the page. These are the resources that block rendering. Since it's important that users see your content as quickly as possible, it's important to know what might be causing your page to render slowly. We recently enhanced the way we measure blocking resources and wanted to share those improvements with our customers as well as the performance community at large.
The main culprits that block rendering are scripts and stylesheets that are loaded synchronously. A great way to avoid this blocking problem is to load your scripts and stylesheets asynchronously. You can do that for scripts by using the async and defer attributes, plus other programmatic techniques. Loading stylesheets asynchronously is less popular but is still possible using techniques like loadCSS.
We recently improved how blocking stylesheets are measured. The first change is to ignore stylesheets loaded via loadCSS; these are asynchronous and thus don't block rendering. Similarly, we ignore stylesheets that are initially loaded with link-rel-preload and later added to the DOM dynamically. Finally, we ignore stylesheets with a "print" media type. If your site uses any of these techniques, then your "Blocking CSS" SpeedCurve metric will decrease.
We also improved how blocking scripts are measured. But before diving into that, I need to explain a subtle difference in how scripts and stylesheets block rendering. Synchronous stylesheets block the entire DOM from rendering. Synchronous scripts, however, only block the elements that follow the SCRIPT tag in the DOM tree. This is illustrated in the figure below where scripts that block rendering are shown in red. Async and defer scripts are always green (non-blocking) no matter where they occur in the DOM. Synchronous scripts, however, block rendering if they occur in the HEAD or in the BODY above any DOM elements that are in the viewport. If synchronous scripts occur below the visible DOM, then they don't block rendering.
This leads to an important optimization in how to measure blocking JS. If a page has a synchronous script at the bottom of the page (below all the visible DOM elements), then it does not block rendering (because all the visible DOM elements precede the SCRIPT tag).
In order to accurately measure blocking scripts, SpeedCurve does more than just track whether scripts are sync or async. We also determine if the script blocks rendering. We do this by determining if the synchronous script occurs before any of the DOM elements in the viewport. If a script is loaded synchronously and occurs before any DOM elements in the viewport, then we count it as "blocking JS". If it occurs after all the viewport's DOM elements, then it is not counted as blocking (even if it's loaded synchronously).
This change may decrease your "Blocking JS" SpeedCurve metric if you have synchronous scripts in the body of the page. It did for us! In the SpeedCurve.com dashboards, all the charts are loaded via synchronous scripts, but all those synchronous scripts are below the visible DOM. So our Blocking JS metric dropped from 4 to 0! This helps us focus on the resources that are most important for improving rendering.
Measuring blocking resources is difficult to do, but it's one of the most important metrics to track if you want to optimize your Start Render time. We're glad we have both of these metrics. We're also glad this code is behind us. Phew!