--- layout: post title: "blocking=render: Why would you do that?!" date: 2024-08-14 12:45:11 categories: Web Development main: "https://csswizardry.com/wp-content/uploads/2024/08/blocking-status.png" meta: "Why on earth would you make something render-blocking?!" faq: - question: "Why would be need a blocking=render attribute?" answer: "Generally, we don’t! The primary use case thus far is to grant scripts the ability to be render- but not parser-blocking, which is not currently possible. This would be particularly helpful for A/B testing libraries who currently rely on anti-flicker snippets to achieve the results they want." --- WebKit have recently announced their [intent to implement](https://github.com/WebKit/WebKit/pull/32022) the `blocking=render` attribute for `` This will block parsing (and therefore also rendering) of subsequent content. The browser may not parse or construct any DOM until `app.js` is fully fetched and parsed, at which point it now has two tasks ahead of it: build the DOM and render it. **Scripts are parser blocking.** All other file types are, by default, non-blocking. The pedant in me wants to point out that even inline ` ``` This snippet works by applying the class `async-hide` to the `` element (`document.documentElement`). This aggressively sets `opacity: 0;` so that the page is rendered, only invisibly. The class is then removed either when the A/B tool’s work is done, or a `4000`ms timeout is reached—whichever is first. One immediate failing with this is that an invisible page is still interactive, and users could still click on or interact with elements inadvertently. The page _is_ rendered, but invisibly. `blocking=render` ensures that the page is not rendered at all, and therefore can’t be interacted with. Another problem is that we’re going through more paint cycles than we need to: paint the page invisibly, modify it, paint it again visibly… It would be nicer to hold off painting anything at all until we have all of the relevant information about what to paint. `blocking=render` gives us this ability. A further issue is the big-reveal phenomenon: with an anti-flicker snippet, the page is totally invisible until it’s totally visible. Behind the `opacity: 0;`, there may well have been a progressive render of the page—which is a familiar and good user experience—but a user didn’t benefit from it. Anti-flicker snippets eschew this behaviour and take an all-or-nothing approach: nothing, nothing, nothing, _everything_.
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 `4000`ms 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](https://github.com/whatwg/html/issues/7131#footnote2), 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: * `` - - - [^1]: [x.com/kurtextrem/status/1823698340388782591](https://x.com/kurtextrem/status/1823698340388782591)