We've all heard of the 'eliminate render blocking resources' recommendation in Lighthouse. But to understand why it is important to fix this, it first is convenient to know a few basic principles of browsers.
This is an easy-to-understand principle for both developers and SEO & UX specialists. The browser has two tasks in the following order.
- Parsing = analyzing HTML to figure out what to construct and what to download.
- Rendering = drawing pixels to your screen based on HTML + CSS construction.
This is a simplified explanation, let’s get a bit more in-depth.
What happens before the parsing process
When we type in an URL and press enter the server responds with an index.html. However, we don’t see lines of codes from the HTML file. We see a page with colors, backgrounds, animations, and pictures. Without us noticing the browser parsed and rendered the HTML in a pretty web page, so we get to see a page that we can actually use.
The HTML parsing process
So, at the start, we have HTML content that goes through a tokenization process. Tokenization is a common process in almost every programming language in which code is split into several tokens that are easier to understand while parsing. This is where the HTML parser determines the start and end of the tag, as well as which tag it is and what is contained within it.
Now that we know that the HTML tag begins at the top and the head tag begins before the HTML tag ends, we can determine that the head is contained within the HTML tag and construct a tree from it. As a result, we get a parse tree, which eventually becomes a DOM tree.
What happens to CSS?
CSS, like HTML, follows a similar path, beginning with CSS text and ending with CSS tokenization to produce something called a CSS Object Model (CSSOM).
Now that we have the DOM and CSSOM, we got what we need to paint pixels onto the screen.
Let’s render the page
When the render process starts, the DOM and CSSOM will be merged to create a render tree. The render tree has everything it needs to paint the elements on the screen.
Included during rendering
Although one might not expect the following, elements with ‘opacity: 0
’, ‘visibility: none
’ or ‘display: none
’ will still be rendered. Even though not being visible for users. And that could take up valuable time, delaying other tasks which might be more important for FCP and general user engagement.
You could test this by applying one of the above CSS properties to a (non-lazyloaded) image. When looking at your network panel in DevTools, you'll notice that images with such CSS will still be downloaded. Actually a good first reason to lazyload (most of your) images.
Excluded from rendering
Elements like head
and anything that goes within it (such as link
, script
) are ignored, since they aren’t rendered on the screen. The `content-visibility: hidden
` also is excluded from rendering. As a result, the use of the CSS property content-visibility
could improve pagespeed.
Putting things together
Now the browser got everything that it needs to create a visually good-looking web page. The whole process of parsing and rendering will look like this:
- HTML is being loaded;
- HTML is being parsed;
- The browser will detect resources, such as CSS files;
- These will then be downloaded;
- And parsed;
- To attach styles to HTML elements (DOM nodes);
- Which will result in styled page.
Delayed parsing and rendering
Although `content-visibility: hidden
` will skip rendering of its own element and all child elements, it is still being parsed as it is still part of the (initial) HTML. This often doesn't have to lead to issues.
However, large HTML documents could lead to chunked HTML when the browser doesn't receive all HTML at once. This is parsing + potentially dispatching delay. This means browsers will detect resources later than desired if important resources were pushed down in the source code due to large inlined codesnippets (often CSS and JS). Those important resources then won't be part of the first chunks yet.
It especially becomes harmfull when those resources are then parse or render blocking themselves as well. Then a combination of multiple bottlenecks is being introduced.
Summarizing parse and render blocking
So, let's summarize:
Parse blocking
Inlined or non-deferred JS will pause parsing. Hence, parse blocking (and this will also be render-blocking).
Render blocking
Most browsers moved to making CSS both parse and render blocking as well. Especially in Chromium browsers.
It makes sense that CSS is render blocking: the browser needs the CSS to know where pixels should go (position, color, font family). The bigger your CSS, the bigger your (FCP) bottleneck will be because of download time and amount of pixel/rendering work. This CSS is then considered a render-blocking resource.
Inlined CSS is also render blocking, but it's inlined so technically it then isn't a render blocking resource. You're then just saving a round trip and improve pagespeed when implementing critical CSS.