Render-blocking scripts or stylesheets in the head
What is this issue?
The page's <head> loads files that the browser must download — and, for
scripts, run — before it can paint anything on screen.
Two kinds of tag do this:
- A synchronous script:
<script src="...">withoutasyncordefer. The browser stops reading the page, fetches the script, runs it, and only then carries on. - A stylesheet:
<link rel="stylesheet" href="...">. The browser will not paint until it has the CSS, so the page does not flash unstyled.
For a page to pass this check:
- Every script in the
<head>isasync,deferortype="module". - No more than two stylesheets in the
<head>block the first paint.
Why stylesheets get an allowance. Blocking on CSS is intended behaviour —
without it, visitors would see a flash of unstyled content. One or two
stylesheets (the site's own, plus perhaps a font or framework sheet) are
normal. The problem is the head with a stylesheet per plugin, every one of
which must arrive before the first pixel. Scripts get no allowance: a script in
the head that needs to block rendering is rare, and defer fixes most of them.
What is not counted: scripts at the end of the <body> (the classic fix),
type="module" scripts (deferred by definition), nomodule scripts (skipped by
modern browsers), data blocks such as application/ld+json structured data,
and stylesheets whose media cannot match a screen (print, speech,
not all) or that are disabled or alternate.
Why it matters
Nothing appears until they arrive. Each blocking file adds at least one network round trip before First Contentful Paint. On a mobile connection that is hundreds of milliseconds per file, and the visitor sees a blank screen the whole time.
Largest Contentful Paint follows. The main content cannot paint before the first paint. Render-blocking resources are one of the most common reasons a page fails the LCP threshold in Core Web Vitals.
Third-party scripts make it unpredictable. A synchronous script from another domain ties your page's first paint to that domain's speed and availability. If it is slow, your page is slow; if it is down, your page can hang.
Lighthouse reports it. "Eliminate render-blocking resources" is a standard Lighthouse opportunity, and Google's page experience signals reward pages that paint quickly.
Effect on the health score
This is a standard issue. It deducts from the Delivery & Trust score for each affected page.
How to fix it
Scripts
Add defer to scripts that work with the page's content. They download in
parallel and run, in order, after the HTML is parsed:
<!-- Before -->
<script src="/js/app.js"></script>
<!-- After -->
<script defer src="/js/app.js"></script>Use async for independent scripts such as analytics, which do not depend on
other scripts or on the DOM:
<script async src="https://www.googletagmanager.com/gtag/js?id=G-XXXX"></script>Or move the script to the end of the <body>.
Stylesheets
Inline the critical CSS — the rules needed to render the top of the page — in a
<style>block, and load the full stylesheet without blocking:<style>/* critical above-the-fold rules */</style> <link rel="stylesheet" href="/css/site.css" media="print" onload="this.media='all'"> <noscript><link rel="stylesheet" href="/css/site.css"></noscript>Combine stylesheets that are always used together into one file.
Remove what the page does not use — plugin stylesheets loaded on every page for a feature that appears on one.
Give print styles
media="print"so they never block the screen.
Examples
Example 1: A synchronous script
<head>
<link rel="stylesheet" href="/css/site.css">
<script src="/js/jquery.min.js"></script>
</head>Reported: one synchronous script. The single stylesheet alone would pass.
Example 2: Deferred and async scripts
<head>
<link rel="stylesheet" href="/css/site.css">
<script defer src="/js/app.js"></script>
<script async src="https://analytics.example.net/a.js"></script>
<script type="application/ld+json">{"@context":"https://schema.org"}</script>
</head>Passes.
Example 3: Too many stylesheets
<head>
<link rel="stylesheet" href="/wp-content/plugins/slider/slider.css">
<link rel="stylesheet" href="/wp-content/plugins/forms/forms.css">
<link rel="stylesheet" href="/wp-content/plugins/gallery/gallery.css">
<link rel="stylesheet" href="/wp-content/themes/site/style.css">
</head>Reported: four blocking stylesheets, two more than allowed.
Example 4: Non-blocking stylesheets
<head>
<link rel="stylesheet" href="/css/site.css">
<link rel="stylesheet" href="/css/fonts.css">
<link rel="stylesheet" href="/css/print.css" media="print">
<link rel="stylesheet" href="/css/rest.css" media="print" onload="this.media='all'">
</head>Passes: two blocking stylesheets; the print-media ones do not block.
How PixyScan detects this
Reads the HTML the server sent, not the page after JavaScript ran. When a scan renders pages in a browser, scripts and stylesheets that JavaScript adds later appear in the head without
async, although they never blocked the first paint. So PixyScan asks the browser for the original response and reads its<head>. If that is not available for a page, the page is skipped for this check rather than judged on the wrong document.Finds blocking scripts in the
<head>:<script>with asrc, a JavaScript type (notype, or a JavaScript MIME type such astext/javascript), and neitherasyncnordefer. Skipstype="module",nomodule, and any othertype(application/ld+json,text/template, ...), which the browser does not run.Finds blocking stylesheets in the
<head>:<link>whoserelincludesstylesheet(in any case) but notalternate, with anhref, notdisabled, and amediathat could match a screen.mediais judged by its media type:print,speechandnot alldo not match;all,screen,not printand queries such as(min-width: 600px)might, so they count.Ignores content inside
<noscript>and<template>, which is not loaded.Reports when there is at least one blocking script, or more than two blocking stylesheets.
Records both counts and up to five of the URLs, resolved to full addresses, scripts first.
What we store
Storage Level
Page Level
Database Table / Prisma Model
audit_issues.details
Stored Fields
| Field | Type | Description |
|---|---|---|
| message | String | How many scripts and stylesheets block the first paint |
| blockingScriptCount | Int | Synchronous scripts in the head |
| blockingStylesheetCount | Int | Render-blocking stylesheets in the head |
| sampleUrls | String[] | Up to five of the blocking URLs, resolved, scripts first |
| stylesheetAllowance | Int | How many blocking stylesheets are allowed (2) |
Detection Dependencies
- The HTML document as served by the server
Note
Kept on the finding only. The counts describe one page's markup and are not stored in a column of their own.