Perceived Web Performance - What Is Blocking the DOM?
When it comes to web performance and optimizing speeds on a page-level basis it is very important to understand the relationship between HTML and how a page is actually constructed in your browser, so that you can pinpoint delays in page loads due to render blocking. In this post, we will dig deeper into what is blocking the DOM and ways you can prevent it from happening.
What is the DOM?
The DOM is an acronym for Document Object Model. It is a programming interface for HTML and XML documents and provides a structured representation (node tree) of a document, defining ways it can be accessed and manipulated using scripting languages such as JavaScript. A node tree is made up of different elements, parents, children, siblings, etc. and they all have a hierarchical relationship with each other. Below is an example of an HTML DOM.
DOM in laymen terms
To put it simpler, when you are using a tool like Chrome DevTools, this is showing you a visual representation of the DOM. Your plain HTML is not the DOM, Chrome DevTools shows you the DOM after it has been manipulated, by HTML or JavaScript. You can also think of it as the parsed HTML.
What is blocking the DOM?
When it comes to analyzing the speed of your web pages you always need to take into consideration what might be blocking the DOM, causing delays in your page load times. These are also referred to as render blocking resources, such as HTML, CSS (this can include web fonts), and JavaScript.
One of the easiest ways to see what is currently blocking the DOM is to use Chrome DevTools and PageSpeed Insights. In our examples below we are using the latest developer tools in Chrome Canary.
- Launch developers tools in Google Chrome.
- Windows:
F12
or alsoCtrl
+Shift
+I
- Mac:
Cmd
+Opt
+I
- Windows:
- Browse to the "Network" panel and refresh the page by pressing
Ctrl
+R
(Cmd
+R
). - You will now see a waterfall with load times. There are two things we want to look at here, first is the total DOMContentLoaded, which is 342 ms and then also the resources that are before (left of) or touching the blue line.
Since we know CSS and JavaScript are both render blocking resources, and they are loading before/on the blue DOMContent line, we can assume they are blocking the DOM. Remember, images aren't render blocking so if you have images on the blue DOM line you can safely ignore those; although you will still want to optimize your images. In this example below we can see that the style.css
file and the jquery.min.js
file are both blocking the DOM.
You can also verify this information by running it through Google PageSpeed Insights. As you can see below it confirms both of these files are render blocking.
Follow the recommendations below on how you can prevent your CSS and JavaScript from blocking the DOM by optimizing your critical rendering path. While HTML is also a render blocking resource, the DOM can be built incrementally.
Note, it is not always necessary to go for that 100/100 score on PageSpeed Insights. For example, if you link to a Google web font using their external fonts.googleapis.com
style sheet this is always going to be a render blocking resource, no matter what you do. The important thing is to recognize how to fix them so that on larger sites when you are dealing with 10+ files blocking the DOM you understand what is causing delays and have strategies in place to more efficiently load them.
CSS
Non-render blocking CSS
If you are going for completely non-render blocking CSS then you really only have one good option, and that is to inline your CSS. You include the CSS required for the initial rendering, typically styles for the above-the-fold content, directly in the HEAD section in the <style></style>
elements and move the rest of your CSS to the bottom before the </body>
element. This will prevent render blocking.
Inline CSS plugins for automated task systems
- Grunt: grunt-critical-css
- critical
You could also load your CSS using JavaScript, but then you will deal with the page having to repaint at the end of the load, which is not always ideal for the visitor.
As you can see in Chrome DevTools we now inlined our CSS and the DOMContentLoaded was slightly faster at 279 ms.
And now when we test it in Google PageSpeed Insights we no longer have our render blocking CSS.
While this is great, it all depends upon your site. Most sites will not want to inline all of their CSS because depending upon how much CSS you have this could significantly increase the download size of that page. For smaller sites or even possibly landing pages inlining CSS thought could be a good alternative if you are wanting to avoid render blocking completely.
Our CSS recommendations
Even on our KeyCDN homepage we have one render blocking CSS file. However, there are things we have done to improve the load times of our CSS. Below are some recommendations.
- Properly call your CSS files
- Use media queries to mark some CSS resources as non-render blocking
- Lessen the amount of CSS files (concatenate your CSS files into one file)
- Minify Your CSS (remove extra spaces, characters, comments, etc)
- Use less CSS overall
Minify CSS plugins for automated task systems
- Grunt: grunt-contrib-cssmin
- Gulp: gulp-minify-css
JavaScript
Non-render blocking JavaScript
When it comes to JavaScript there are some best practices to always keep in mind.
- Move your scripts to the bottom of the page right before your
</body>
tag. - Use the async or defer directive to avoid render blocking.
Loading JavaScript asynchronously
Async allows the script to be downloaded in the background without blocking. Then, the moment it finishes downloading, rendering is blocked and that script executes. Render resumes when the script has executed.
<script async src="foobar.js"></script>
Deferring JavaScript
The defer directive does the same thing, except it guarantees that scripts execute in the order they were specified on the page. So, some scripts may finish downloading then sit and wait for scripts that downloaded later but appeared before them.
Patrick Sexton has a good example of how to defer loading of JavaScript properly.
- Less the amount of JavaScript files (concatenate your JS files into one file)
- Minify your JavaScript (remove extra spaces, characters, etc)
- Inline your JavaScript if it is small
Minify JavaScript plugins for automated task systems
- Grunt: grunt-contrib-uglify
- Gulp: gulp-uglify
By moving our JavaScript to the bottom and adding the async directive we were able to get the DOMContentLoaded down significantly to 144 ms. As you can see the jquery.min.js
file now appears after the DOM blue line.
In Google PageSpeed Insights after we loaded our JavaScript asynchronously, it is no longer considered render blocking and we were able to achieve a 100/100 score.
Web fonts
Web fonts can also be a render blocking resource as they are loaded with CSS. You really have two choices, either block the render or repaint later (then you have to deal with FOUT). For example, in Chrome (36+), Opera (23+), and Firefox there is a three-second timeout, after which the fallback font is shown.
There are a couple recommendations when it comes to loading fonts and optimizing the critical rendering path.
- Use a web font loader or font loading API
- Optimize font loading with inlining
- Use other storage methods such as localStorage
See our post on analyzing web font performance to see a more in-depth explanation of the different options you have for loading web fonts so you avoid render blocking and FOUT/FOIT.
Summary
So hopefully now you understand a bit better what it means when you hear the term, blocking the DOM, and how the construction of the DOM tree can be delayed by render blocking CSS JavaScript, and even web fonts. Remember it might not always be possible to score that 100/100 on PageSpeed Insights, the important thing to understand is how your render blocking resources block the DOM and how you can properly optimize and deliver them for faster page speeds.