Render-blocking resources: what blocks first paint
Render-blocking resources are the stylesheets and scripts in head a browser must load before its first paint. Which ones count, and how to unblock them.
Render-blocking resources are the files a browser has to download and process before it can paint anything: stylesheets in <head> and classic scripts in <head> without async or defer.
Lighthouse’s criteria are specific. A <link rel="stylesheet"> blocks unless it is disabled or its media does not match the device. A <script> in <head> blocks when it has neither defer nor async. A type="module" script is deferred by default.
Category: Performance
Why it matters
The browser will not paint until it has every matching stylesheet, and a parser-blocking script stops everything after it until it has downloaded and run. That time sits in front of the first paint and of Largest Contentful Paint. Chains make it worse. An @import inside a stylesheet names a file the browser cannot discover until the first file has arrived and been parsed, so each link costs another round trip, and a faster connection does not shorten round trips. A file on a new origin also waits for DNS, TCP and TLS before its first byte, which rel="preconnect" can start early.
How squirrelscan checks it
perf/render-blocking counts the blocking stylesheets and scripts in <head> and lists each URL. A stylesheet counts only when it has no media attribute at all, so even media="all", which still blocks paint, removes it from the count. Check the listed URLs rather than the number. perf/critical-request-chains counts the stylesheets in <head> that are neither media="print" nor disabled, the blocking scripts there, plus every @import a browser would fetch from the page’s <style> blocks. It counts resources, not measured chain depth, since a static read cannot see what a stylesheet fetches once it loads. perf/preconnect checks thirteen common CDN hosts, such as fonts.googleapis.com and cdn.jsdelivr.net, for a missing preconnect.
| Rule | What it flags | Severity |
|---|---|---|
| Render-blocking resources: the ones squirrel counts in head | Stylesheets and scripts in head that hold up first paint. squirrel counts them per page and lists each URL. | warning |
| Critical request chains: the blocking head resources counted | Blocking stylesheets and scripts in head, plus every inline CSS @import a browser fetches. squirrel counts each as a link in the chain before first paint. | warning |
| rel=preconnect: the CDN origins squirrel checks for a hint | A page loading from a known CDN with no preconnect for that origin. squirrel checks thirteen common hosts. | info |
How to fix it
Inline what the first screen needs, load the rest without blocking, and defer scripts:
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<style>/* styles the first screen needs */</style>
<link rel="stylesheet" href="/rest.css" media="print" onload="this.media='all'" />
<script src="/app.js" defer></script>The media="print" stylesheet downloads without blocking and switches on once loaded (the render-blocking fix). Replace each @import with its own <link>, so the browser fetches the files in parallel (the request chain fix). Preconnect to two to four origins on the critical path at most, with crossorigin for fonts (the preconnect fix).
Run the check
squirrel audit https://example.com --rule-include perf/render-blocking,perf/critical-request-chains,perf/preconnectA signed-out local audit costs nothing.
Related terms
- Largest Contentful Paint (LCP): The time until the largest image or text block in the viewport renders; good is 2.5 seconds or less.
- font-display: The @font-face descriptor (swap, optional, fallback) that decides what text shows while a web font loads.