Why would you do that?! – Web Performance and Site Speed Consultant


Written by on CSS Wizardry.

Table of Contents
  1. What is blocking=render?
  2. Blocking Status
    1. Blocking Files
    2. async, defer, and type=module
  3. Blocking Web Fonts
  4. A/B Testing and Experimentation
  5. tl;dr

WebKit have recently announced their intent to
implement the blocking=render
attribute for

The blocking=render attribute allows developers to explicitly mark a resource
as render blocking, but… why on earth would you want to do that?!

The short answer is: generally, you wouldn’t. Unless you know you need
this behaviour, you don’t need it.

But how do you know if you do need it? Read on…

Table of Contents

What is blocking=render?

The spec says:

A blocking attribute explicitly indicates that certain operations should be
blocked on the fetching of an external resource. The operations that can be
blocked are represented by possible blocking tokens, which are strings listed
by the following table […]
— 2.5.8 Blocking attributes

Currently, there is only one token specified: render. The spec is extensible
so that other values could be added as the need arises—potential scenarios that
have been
discussed
include parse, load, and even a negation to encourage the opposite, such as
blocking=!render.

Blocking Status

Generally speaking, when loading resources into web pages, there are three
possible blocking states:

  1. Non-blocking: From a performance perspective, this is the most desirable.
    The resource is fetched and processed asynchronously while the browser is
    free to work on whatever other tasks there may be. The two key tasks that are
    not blocked are rendering and parsing.
  2. Render blocking: The next-best option for the performance conscious is
    render blocking. Files that are render blocking prohibit the browser from
    presenting the page, but do permit the browser to at least construct it.
  3. Parser blocking: The worst case scenario is a file that prevents the
    browser from even building the page. All parsing and rendering is blocked
    while the resource is fetched. Files that are parser blocking are inherently
    also render blocking—the browser can’t present a page that it can’t even
    construct.

Visually, this is how that process looks for each scenario:

Comparison of non-blocking, render-blocking, and parser-blocking resources in web performance. A visual breakdown of how different loading strategies affect rendering, parsing, and blocking behaviour in the browser.
A non-, render-, and parser-blocking file in an HTML document. Imagine the
downloading file (pink) is in the —even though you can
never see tags or their children, they still get
rendered just like any other HTML, they’re just set to display:
none;
. That said, these diagrams also apply to a downloading file (pink)
that is in the middle of the . HTML is parsed
line-by-line and is very predictable. We ❤️ HTML.

Blocking Files

The two main file types that impact the blocked status of a web page are
stylesheets and scripts. In their default states:

  • : This will block the rendering of
    subsequent content, but not its parsing. The browser is free to continue
    parsing the HTML and building out the DOM, but cannot display any of it until
    app.css is fully fetched and parsed. Stylesheets are render blocking.

All other file types are, by default, non-blocking.

The pedant in me wants to point out that even inline

A digital stopwatch running an HTML file, displaying ‘00:51’ in large green text before unceremoniously changing its typeface and continuing to count down.
The change from fallback font to web font causes a very noticeable
change in UI. This might be unacceptable.

Given a UI such as this, even with the best will in the world, the switch from
any fallback font to the intended web font is quite a leap. Is it too much? If
you decide it is, you could block on the preload of that font (if you were
preloading it in the first place). That would look like this:

 rel=preload
      as=font
      href=font.woff2
      crossorigin
      blocking=render>

Typically, I would strongly recommend not blocking rendering on web fonts. Using
the relevant font-display to ensure that text can render as soon as possible
is almost always the correct thing to do: reading something in the ‘wrong’ font
is better than reading nothing at all.

However, in scenarios where a flash of fallback font (FOFT) might be
particularly jarring—or create severe layout shifts—then perhaps waiting on the
web font might (might) be the right thing to do. Maybe. I’m not actively
recommending it.

Note that almost the exact same behaviour could be achieved by adding
font-display: block; to the relevant @font-face rule, but blocking=render
provides two distinct additions:

  1. font-display: block; will time out after three seconds, whereas
    blocking=render has no such timeout. In that sense, it’s much more
    aggressive.
  2. font-display: block; will still render the current UI, only without text—a
    flash of invisible text (FOIT). blocking=render won’t render anything at
    all.

If a web font is your content (which, for 99.999% of you, it isn’t), you might
want to maybe use blocking=render. But even then, I wouldn’t.

A/B Testing and Experimentation

blocking=render’s application in client-side A/B testing is, for me, its most
compelling use-case.

Client-side A/B testing tools work by altering the DOM and presenting a variant
of a component to a user. In order for this to work, the original DOM must
already be constructed (you can’t alter a DOM if you don’t have one), so there’s
an aspect of doing the work twice. A problem arises if and when a user actually
sees that work happening twice. It’s a jarring experience to see one version
of a hero change to something completely different in front of your eyes, and it
may even influence the outcome of the experiment itself.

To circumvent this, many A/B testing tools implement what is known as an
anti-flicker snippet. They deliberately hide the page (visually) until the
variants have been constructed, or a timeout is met—whichever happens sooner.

This is the anti-flicker snippet from the now
defunct Google
Optimize.



  .async-hide { opacity: 0 !important }



Progressive rendering sequence of a webpage displaying a web performance consultancy service. The timeline from 0.8s to 1.7s shows how content and images load incrementally, highlighting the impact of rendering delays.
A regular, progressive render (top) versus an anti-flicker
big-reveal (bottom). Which do you think is the better experience?

blocking=render leaves the browser to its usual rendering process, so we can
still get a progressive render of the page, only now we do it in a way more
akin to loading a CSS file.

Finally, and this is counter to my own preferences and beliefs as a performance
engineer, we still risk leaking the experiment to the user when using an
anti-flicker snippet. Knowingly hiding a page for up to four seconds feels like
insanity to me, but at least we do have a timeout. The problem with anti-flicker
snippets is that if that four-second timeout is reached, we’ll still display the
page even if experiments haven’t completed—the 4000ms is a magic number that
we use to hopefully win a race condition.

By using blocking=render, that timeout now becomes governed by the browser’s
own heuristics, which is
almost definitely going to be longer than four seconds. While that does terrify
me, it does guarantee we don’t paint anything too soon. No more race
conditions, but a potentially longer render-blocked period.

As I said at the top of the article, most of us won’t need blocking=render,
and those of us who do will know that we do.

tl;dr

One handy takeaway is that, at present, blocking=render would cause any of the
following:

…to behave like this:



Share this content:

I am a passionate blogger with extensive experience in web design. As a seasoned YouTube SEO expert, I have helped numerous creators optimize their content for maximum visibility.

Leave a Comment