Render-blocking resources: why your page is blank before it paints
Render-blocking resources are the CSS and JavaScript files that stop the browser from painting anything on screen until they’ve finished loading. Two kinds block by default: every stylesheet in the head, because the browser won’t paint until it knows how the page should look, and every script in the head without async or defer, because a synchronous script freezes HTML parsing to run. The cost lands on the metrics people feel — the median site carries about seven render-blocking resources that add 500 to 1,500 milliseconds to LCP on mobile, and your content can be downloaded and ready while the screen stays white. The fixes are a ladder: delete the dead stylesheets and scripts still sitting in the head, give every non-critical script defer, async the third-party ones, and — the advanced move — inline the small slice of critical CSS needed to paint above the fold (kept under about 14KB) while loading the rest asynchronously. All of it works, and all of it is effort spent unblocking a page you loaded up in the first place — which is why a static site that ships one small stylesheet and almost no JavaScript barely blocks at all: the critical path is short because it was never lengthened.
What does “render-blocking” actually mean?
Render-blocking resources are files that prevent the browser from displaying anything on screen until they finish downloading and processing (Panstag, 2026). The rule browsers follow is strict: no pixels appear until all render-blocking resources are done, which produces the counterintuitive situation where the browser already has your content but refuses to show it (Unlighthouse, 2026). While a page might request dozens or hundreds of files, only a handful — the critical ones — block rendering completely (DebugBear, 2026).
Understanding why means knowing the critical rendering path: the browser parses HTML into a DOM, parses CSS into a CSSOM, combines them into a render tree, lays it out, and paints (the7eagles, 2026). Anything that stalls a step in that chain stalls the paint at the end of it. To speed the path up, you minimise the number and size of render-blocking resources, prioritise above-the-fold content, and defer anything not needed for the first render (DebugBear, 2026).
Why is CSS render-blocking by default?
Because the browser can’t safely paint without knowing the styles. CSS is render-blocking by default: the browser waits for the complete CSSOM before painting, since it needs the styles to know what each element should look like (LemmiLink, 2026). Every <link rel="stylesheet"> in the head blocks rendering unless it carries a media attribute that doesn’t match the current device — a media="print" stylesheet, for instance, won’t block rendering on a screen (corewebvitals.io, 2026).
This is why CSS bloat is so costly to first paint. If a page links three stylesheets totalling 400KB, the browser paints nothing until all three arrive, even though most of that CSS styles content far below the fold (LemmiLink, 2026). The browser is being cautious on your behalf — but the caution shows up to your visitor as a blank screen.
Why does a script in the head freeze the page?
Because synchronous JavaScript is parser-blocking. Any <script> tag without async or defer halts HTML parsing entirely: the browser stops, downloads the script, executes it, and only then resumes reading the page (SiteGrade, 2026). Every one of those stop-download-execute-resume cycles adds delay before the first paint (the7eagles, 2026).
The web is still full of these. The 2024 Web Almanac found that only 49% of individual script tags use async and just 13% use defer, meaning most scripts on the web still load in a way that blocks rendering (corewebvitals.io, 2026). Common culprits are large libraries: jQuery, at 30KB or more, is render-blocking by nature and is often the single largest script on a site (Perfmatters, 2026).
How much does it actually cost?
More than most people expect, and directly on the metrics Google measures. The median website loads seven render-blocking resources totalling over 100KB, adding 500 to 1,500 milliseconds to LCP on a typical mobile connection (Unlighthouse, 2026). The sharpest way to see it: your LCP image might download in 200 milliseconds, but if 300KB of CSS is still loading, the user sees nothing — the browser has the content and refuses to display it (Unlighthouse, 2026).
The gains from fixing it are measurable in money, not only milliseconds. Vodafone reduced render-blocking JavaScript and saw a 31% improvement in LCP, which translated to an 8% increase in sales, and monitoring data shows sites that eliminated all render-blocking resources improved their First Contentful Paint by an average of 420 milliseconds (corewebvitals.io, 2026). The clock on LCP is running the whole time the browser is blocked, even though the LCP element isn’t visible yet — which is why this sits upstream of the loading metrics in our pillar on Core Web Vitals and site speed.
Fix one: remove what you don’t need
The best fix is also the simplest — delete the resource entirely. Old, unused scripts and stylesheets still sitting in the head are more common than you’d think, and removing them costs nothing in functionality while eliminating their blocking entirely (corewebvitals.io, 2026). To find them, Chrome DevTools’ Coverage panel shows every CSS and JavaScript file with a percentage of unused code on the initial load; files that are 70% or more unused are strong candidates for deferring, splitting, or deleting (Panstag, 2026).
This is the same instinct behind every performance decision we make: the fastest resource is the one you never load. Before optimising how a file loads, the question is whether it needs to load at all — a discipline that shrinks the critical path rather than merely reordering it.
Fix two: defer and async your scripts
For scripts you keep, control when they run. A script with defer downloads in parallel with HTML parsing and executes only after parsing completes, in document order, which makes it the safer default and the right choice for scripts that depend on the DOM (SiteGrade, 2026). A script with async also downloads in parallel but executes the moment it’s ready, in any order, which suits independent scripts like analytics (LemmiLink, 2026).
The one caution is testing. Some legacy scripts expect synchronous execution and access to DOM elements that haven’t parsed yet, so adding defer can break them; the fix is to wrap that initialisation in a DOMContentLoaded listener rather than relying on script position (Unlighthouse, 2026). Third-party scripts — the analytics tags, pixels and widgets — are the prime targets to async or delay, which is the same argument our guide on third-party scripts and performance makes at length.
Fix three: inline critical CSS (the advanced one)
CSS is harder to defer than script, because a deferred stylesheet renders the page unstyled first and applies the styles once loaded, causing a flash and layout shift (corewebvitals.io, 2026). The technique that avoids this is critical CSS: extract the minimum styles needed to render the above-the-fold content, inline them in a <style> tag in the head so the browser paints immediately, then load the full stylesheet asynchronously (corewebvitals.io, 2026). The critical block should stay at or under about 14KB so it fits in the first network round trip (Unlighthouse, 2026).
Two honest caveats keep this in proportion. Inlining too much CSS bloats the HTML and hurts server response time, so only the above-the-fold styles belong inline (Unlighthouse, 2026). And Google is explicit that this is an advanced technique most sites shouldn’t need — inlining CSS can introduce bugs if done wrong, and most sites can hit their performance targets without it (Chrome for Developers, 2026). That last point matters more than it seems, and we’ll come back to it.
How render-blocking touches every vital
Render-blocking’s clearest victim is LCP, but its reach is wider. Eliminating render-blocking resources is often the difference between a 2.3-second and a 3.1-second LCP, and combined with preloading your LCP image and reducing server response time it forms the three-fix stack that resolves most LCP failures (Panstag, 2026). It also touches CLS: JavaScript that runs during load and modifies the DOM causes layout shifts, so deferring it prevents shifts during the critical load window (Panstag, 2026).
Fonts are a related case worth separating. Web fonts don’t block the page from rendering, but they block the text from rendering, governed by the font-display property — and if your LCP element is a text node using a web font, LCP is affected (DebugBear, 2026). That’s the crossover with our guide on self-hosting web fonts: a self-hosted, properly-configured font removes both a render-blocking request and a text-rendering delay at once.
Why a static site barely blocks at all
Read the fix ladder back and the pattern is familiar: remove, defer, async, inline — almost all of it is effort spent unblocking a page you loaded heavily in the first place. Our build starts from the other end. A static site ships one small stylesheet and almost no JavaScript, so there is little in the head to block rendering and nothing that needs deferring — the critical rendering path is short because we never lengthened it.
That’s also why we don’t reach for critical-CSS inlining, the advanced fix that trips up so many sites. The reason it exists is to work around a stylesheet too large to send before first paint — and our CSS is already small enough to send at once without blocking anything worth the wait, so the problem it solves never arises. This is the same convergence that runs through the whole performance cornerstone: the JavaScript you don’t send can’t block parsing, the CSS you keep lean can’t block painting, and the fastest page is the one that gave the browser nothing to wait for.
Frequently asked
- What are render-blocking resources?
- Render-blocking resources are CSS and JavaScript files that prevent the browser from painting any content on screen until they finish downloading and processing. Two kinds block by default: every stylesheet linked in the head, because the browser needs the complete set of styles before it knows what to paint, and every script in the head without an async or defer attribute, because a synchronous script halts HTML parsing while it runs. The result is that a page can have its content fully downloaded and still show a blank screen, because the browser refuses to display anything until the blocking files are done.
- How do render-blocking resources affect Core Web Vitals?
- They mainly delay First Contentful Paint and Largest Contentful Paint, because nothing can appear until they load. The median website carries about seven render-blocking resources totalling over 100KB, which adds roughly 500 to 1,500 milliseconds to LCP on a typical mobile connection. The effect is stark: your LCP image might download in 200 milliseconds, but if 300KB of CSS is still loading, the user sees nothing. Render-blocking scripts can also cause layout shifts if they modify the page during load, so the impact reaches CLS as well.
- What's the difference between async and defer?
- Both let a script download in parallel instead of blocking HTML parsing, but they execute differently. A script with defer downloads alongside parsing and runs only after the document is fully parsed, in document order — the safer default, and the right choice for scripts that depend on the DOM or on each other. A script with async runs as soon as it finishes downloading, in any order, which suits independent scripts like analytics. Any script tag in the head with neither attribute blocks parsing entirely while it loads and runs.
- What is critical CSS?
- Critical CSS is the minimum set of styles needed to render the visible, above-the-fold part of a page. The advanced optimisation is to inline that small block directly in a style tag in the head, so the browser can paint immediately, while loading the full stylesheet asynchronously. The critical block should stay at or under about 14KB so it fits in the first network round trip. It's genuinely advanced, though — Google notes that most sites can hit their performance targets without inlining CSS at all, and over-inlining bloats the HTML and hurts server response time.
- How do I find render-blocking resources on my site?
- Run Lighthouse or PageSpeed Insights and look for the 'Eliminate render-blocking resources' audit, which lists every CSS and JavaScript file delaying first paint along with the estimated time you'd save. Chrome DevTools' Coverage panel shows how much of each CSS and JavaScript file is actually unused on the initial load — files that are 70% or more unused are strong candidates for deferring or removing. A request waterfall in a tool like WebPageTest or DebugBear marks each blocking resource directly.