Render-Blocking Resources: Get the First Paint Out Sooner
Before the browser can paint anything, it needs the HTML and every stylesheet that applies to the
page. It also stops parsing the HTML whenever it meets a plain <script src> tag, downloads the
script and runs it, and only then carries on. These files are called render-blocking: while they
load, the visitor sees a blank screen.
Why it matters
Each render-blocking file adds at least one network round trip before the first paint. On a mobile connection that can be hundreds of milliseconds per file, and it delays both First Contentful Paint and Largest Contentful Paint. Large stylesheets make it worse: the browser must download and parse the whole file, even if the first screen uses a fraction of it.
How to fix
Defer scripts
Almost no script needs to run before the page is shown. Add defer (runs in order after the HTML
is parsed) or async (runs as soon as it arrives, in any order):
<script src="/js/app.js" defer></script>
<script src="https://analytics.example.com/tag.js" async></script>
Use defer for your own scripts that depend on each other or on the DOM, and async for
independent scripts such as analytics. Scripts with type="module" are deferred by default.
Inline critical CSS, load the rest later
Put the small set of rules needed for the first screen (header, hero, layout) in a <style> block
in the head, and load the full stylesheet so it doesn’t block the first paint. Build tools and
optimisation plugins can extract the critical rules for you. Keep the inlined part small: it is
sent with every HTML response and isn’t cached on its own.
Use the media attribute
A stylesheet whose media query doesn’t match is still downloaded, but it doesn’t block rendering:
<link rel="stylesheet" href="/css/print.css" media="print" />
<link rel="stylesheet" href="/css/wide.css" media="(min-width: 1024px)" />
Splitting print or large-screen styles into their own files keeps them off the critical path.
Remove unused CSS
Themes and page builders often ship one large stylesheet for every page and every widget. The browser still has to download and parse all of it before painting. Remove rules you no longer use, split styles per template or component, and don’t load a plugin’s stylesheet on pages that don’t use the plugin.
WordPress
Since WordPress 6.3, scripts can be enqueued with a loading strategy:
wp_enqueue_script('my-theme', get_template_directory_uri() . '/js/theme.js', [], '1.2.0', [
'strategy' => 'defer',
'in_footer' => true,
]);
For plugin and theme assets you don’t control, optimisation plugins such as Autoptimize, WP Rocket or LiteSpeed Cache offer options to defer JavaScript, generate critical CSS and remove unused CSS. Test the site after turning these on: deferring a script that inline code depends on can break menus, sliders or forms.
Nginx, Apache and Cloudflare
Render blocking is decided by the HTML, so there is no server setting that fixes it. The server can still help by making the remaining blocking files arrive faster: enable text compression, HTTP/2 or HTTP/3, and long cache lifetimes for versioned CSS and JavaScript.
Common mistakes
- Adding
asyncto scripts that depend on each other, such as jQuery and its plugins. Usedeferso they keep their order. - Loading web fonts through a CSS
@importinside another stylesheet, which adds a chain of blocking requests. Use a<link>in the head instead. - Inlining the whole stylesheet. That moves the cost into the HTML rather than removing it.
How PerfoMetrix checks this
We read two audits from the Lighthouse report of the PageSpeed Insights run we already make
(mobile, simulated device): render-blocking requests (render-blocking-insight) and
unused CSS (unused-css-rules). If Lighthouse rates an audit 0.9 or higher, or it doesn’t
apply to the page, the check passes; otherwise it needs attention. We show Lighthouse’s estimate,
such as “Est savings of 1,200 ms”, and the first five files it lists.
These checks are shown but don’t count toward the performance score: their effect is already measured by FCP and LCP, which are scored. No extra requests are made to your site.