Render-blocking requests dans Lighthouse : comment les corriger
Lighthouse 13 liste chaque feuille de style et chaque script attendus par la page avant son premier affichage, y compris les plus rapides. Quand cela fait perdre du temps à vos visiteurs, et quelles solutions CSS fonctionnent.
Les requêtes render-blocking pénalisent-elles votre score ?
Lighthouse liste chaque feuille de style et chaque script attendus par la page avant son premier affichage dans l'insight Render-blocking requests (« Requests are blocking the page's initial render, which may delay LCP »), appelé « Eliminate render-blocking resources » avant Lighthouse 13. Cet insight ne compte pas dans votre score, mais tant que la page attend son CSS et ses scripts, elle reste blanche, ce qui retarde le FCP et le LCP, surtout sur mobile. Allégez et combinez votre CSS, et différez vos scripts.
Table of Contents!
Que vérifie l'insight Render-blocking requests ?
La description de Lighthouse indique : « Requests are blocking the page's initial render, which may delay LCP. Deferring or inlining can move these network requests out of the critical path. » Inliner n'est pas la solution : voir plus bas. Le tableau comporte trois colonnes : URL, Transfer Size et Duration. Transfer Size correspond au fichier compressé tel qu'il a été envoyé. Duration est l'estimation par Lighthouse du temps nécessaire à la requête sur un mobile lent, nouvelle connexion vers un autre domaine comprise.
Pendant le chargement d'une page, Chrome marque chaque requête comme render-blocking ou non, et l'enregistre dans sa trace. Lighthouse lit la trace et liste chaque requête du frame principal que Chrome a marquée comme bloquante et qui s'est terminée avant le premier affichage. En pratique, il s'agit des feuilles de style et des scripts synchrones présents dans le <head>, ainsi que des fichiers qu'ils importent avec @import. Une feuille de style dans le body ne compte qu'avec la priorité la plus haute de Chrome, et un script avec une priorité haute ; après la première image, tous deux passent à une priorité inférieure et sont ignorés. Il n'y a aucun seuil : un seul fichier listé fait échouer l'insight.
Certains fichiers n'apparaissent jamais, même lorsqu'ils ralentissent la page : les scripts async, les fichiers injectés par un script (gtm.js, gtag.js), les styles et scripts inline, tout ce qui se trouve dans une iframe, et les polices.

L'insight sur une page produit WooCommerce, Lighthouse 13.5.0, bridage simulé comme dans PageSpeed Insights.
Qu'est-ce qui rend un fichier render-blocking ?
Render-blocking signifie que le navigateur n'affiche rien tant que le fichier n'est pas là : chaque feuille de style du <head> doit être arrivée, et chaque script synchrone doit être téléchargé et exécuté.
- Un script placé après une feuille de style attend cette dernière. Chrome n'exécute pas un script synchrone tant que le CSS situé au-dessus n'est pas chargé, et le parseur attend le script. Les deux fichiers peuvent se télécharger en parallèle, vous payez tout de même le temps du CSS, puis celui du script.
- Un
@importdémarre tard. Le preload scanner de Chrome repère immédiatement chaque lien dans le HTML, mais il ne découvre un@importau sein d'un fichier CSS qu'une fois ce fichier arrivé. Sur la page produit ci-dessous, la feuille de style importée du thème a démarré à 1,28 s, contre 0,59 s lorsqu'elle était liée depuis le HTML. - Un autre domaine coûte une connexion. Une feuille de style sur fonts.googleapis.com ou sur un CDN nécessite DNS, TCP et TLS avant que son premier octet n'arrive.
| Dans Chrome | Bloque le premier affichage ? |
|---|---|
<link rel="stylesheet"> dans le head | Oui |
la même chose avec fetchpriority="low" | Oui |
la même chose avec media="print" | Non, mais téléchargé quand même |
rel="preload" plus un lien stylesheet vers le même fichier | Oui |
@import dans une feuille de style bloquante | Oui, après son parent |
<script src> dans le head | Oui |
async | Non, mais peut s'exécuter avant l'affichage |
defer, type="module" | Non |
| une feuille de style dans le body | Seulement le contenu situé en dessous |
Les requêtes render-blocking affectent-elles le FCP et le LCP ?
J'ai mesuré l'impact sur une page produit WooCommerce comportant neuf feuilles de style et deux scripts dans le head, sur un mobile connecté en Slow 4G. Dans la version corrigée, le CSS est allégé et combiné en une seule feuille de style de 6,6 ko et les deux scripts sont différés. Une fois chargée, la page est visuellement identique.
FCP
La version originale a affiché son premier rendu à 2,12 s, la version corrigée à 1,39 s.

Avant

Après
Les deux versions à 1,4 s sur le mobile bridé : l'originale est encore blanche.
LCP
Le LCP ne peut pas intervenir avant le premier affichage. Ici, l'élément LCP est la photo du produit, et elle ne peut pas non plus apparaître avant l'arrivée du CSS : avec la correction, le LCP est passé de 2,25 s à 1,91 s. Dans la décomposition du LCP, cette attente correspond à l'element render delay. Lighthouse ne le montre pas : lorsque l'élément LCP est une image, il estime systématiquement le gain sur le LCP à 0 ms. N'en déduisez pas qu'il n'y a aucun effet sur le LCP.
Combien de sites sont concernés et peut-on l'ignorer sans risque ?
Presque tous. State of CWV analyse la page d'accueil de 114 526 sites disposant de données CrUX : 92,8 % ont au moins une requête render-blocking, 91,2 % une feuille de style bloquante et 62,5 % un script bloquant. Lorsqu'ils en ont, la médiane se situe à 8 requêtes et 110 ko, et un site sur cinq en compte plus de 20. (State of CWV comptabilise les feuilles de style et les scripts synchrones dans le head, ce qui correspond fidèlement à la liste de Lighthouse.)
Les sites qui en accumulent beaucoup obtiennent de moins bons résultats sur le terrain. 84,0 % des sites qui n'en ont aucune affichent un bon FCP sur mobile, contre 54,1 % pour ceux qui en ont plus de 20. Mais le serveur explique la majeure partie de cette chute : sur la même plage, le TTFB médian double, passant de 538 ms à 1 114 ms. Répartition selon la rapidité du serveur :

Sites avec un bon FCP sur mobile selon le nombre de requêtes render-blocking et le temps de réponse du serveur. State of CWV, octobre 2026, CrUX p75 sur mobile, bon FCP à 1,8 s ou moins.
- Serveur rapide (TTFB inférieur à 600 ms) : 94 à 97 % ont un bon FCP, quel que soit le nombre de requêtes. Le délai existe toujours : le passage du premier octet au premier affichage prend environ 150 à 200 ms de plus avec 21 requêtes bloquantes ou plus que sans aucune.
- Serveur lent (TTFB de 900 ms ou plus) : la part de bon FCP passe d'environ la moitié des sites (47 à 53 %) avec deux requêtes bloquantes au maximum, à 30 % avec 21 ou plus. Avec un TTFB de 900 ms ou plus, il reste moins de 0,9 s avant le seuil de 1,8 s d'un bon FCP : chaque requête supplémentaire attendue par l'affichage peut faire basculer le FCP dans le rouge.
Les sites WordPress en comptent davantage : 57 % ont 16 requêtes bloquantes ou plus (médiane à 19, 163 ko). À vitesse de serveur égale, cela coûte 3 points de bon FCP par rapport à une à cinq requêtes sur un hébergement rapide, et environ 10 points sur un hébergement lent.
C'est une corrélation, mais elle fixe les priorités : avec un TTFB lent, réglez d'abord le problème côté serveur. Sur un serveur rapide, ces 150 à 200 ms restent bonnes à prendre lorsqu'il s'agit de votre propre CSS. Vous pouvez ignorer l'avertissement lorsque :
- Lighthouse ne liste qu'une ou deux petites feuilles de style qui vous appartiennent, chacune sous les 15 ko environ ;
- le fichier listé est un outil de consentement, un snippet de test A/B ou un fichier de plateforme que vous ne pouvez pas modifier (voir plus bas).
Comment repérer les requêtes render-blocking dans vos field data ?
Lighthouse charge votre page une seule fois, cache froid. Après leur première page, vos visiteurs ont le CSS dans leur cache : sur le terrain, l'impact se fait donc surtout sentir sur la première page vue. Dans CoreDash, surveillez deux éléments sur mobile :
- L'écart entre FCP et TTFB. Les fichiers render-blocking font perdre du temps entre le premier octet et le premier affichage. Un gabarit où cet écart est plus grand que sur les autres en charge davantage.
- Le LCP render delay. Repérez les gabarits où le render delay représente une part importante du LCP. Le CSS bloquant est l'une des causes de cette attente ; DevTools (section suivante) montre si la page en contient.
CrUX fournit les mêmes métriques au p75 pour votre origine ou une URL précise, sans toutefois indiquer quel gabarit est lent.

CoreDash sur une boutique d'exemple, acme-pagespeed.com, mobile, p75 : les pages produit et catégorie sont les plus lentes.
Comment trouver les fichiers bloquants dans DevTools ?
Ouvrez la page dans Chrome, allez dans le panneau Performance, réglez le réseau sur Slow 4G et le processeur sur un ralentissement 4x, puis enregistrez un rechargement. La barre latérale Insights liste Render-blocking requests. Cliquez dessus et DevTools met en évidence chaque requête bloquante sur la piste Network.

Chaque barre s'étend du démarrage de la requête jusqu'à l'arrivée de son dernier octet. Repérez la requête qui se termine en dernier avant le marqueur FCP : c'est elle que l'affichage a attendue. Une requête CSS qui ne commence que lorsqu'une autre se termine est un @import. Quand rien ne bloque, la barre latérale affiche « No render-blocking requests for this navigation ».
Comment corriger les requêtes render-blocking ?
L'URL dans le tableau Lighthouse indique d'où vient chaque fichier, ce qui détermine où intervenir.
Vos propres fichiers CSS et scripts
Dans vos propres gabarits, visez cette structure de head : une seule petite feuille de style allégée et l'ensemble des scripts différés. Le premier affichage n'attendra alors plus que ce seul fichier.
<link rel="stylesheet" href="/css/main.min.css">
<script src="/js/jquery.min.js" defer></script>
<script src="/js/gallery.min.js" defer></script> La méthode pour y parvenir est détaillée plus bas, en commençant par Alléger et combiner le CSS.
WordPress
Les fichiers sous /wp-content/plugins/ appartiennent à une extension, /wp-content/themes/ à votre thème et /wp-includes/ au cœur de WordPress.
Si vous ne touchez pas au code, utilisez une extension d'optimisation avec ces réglages :
- Activez le différé des scripts : Load JavaScript deferred dans WP Rocket, Defer JavaScript dans Perfmatters, Load JS Deferred dans LiteSpeed Cache. Un script différé ne bloque plus le premier affichage. Attention toutefois à jQuery, voir plus bas.
- Laissez Load CSS Asynchronously et le critical CSS désactivés, peu importe ce que dit la vieille astuce WordPress sous cet audit recommandant des extensions qui « inlinent les assets critiques ». Le critical CSS fonctionne, mais le reste du CSS arrive après le premier affichage : la page applique donc son style en deux temps et subit souvent des décalages de mise en page. Ce que l'inlining coûte en plus est expliqué sous Alléger et combiner le CSS.
- Laissez Remove Unused CSS désactivé (Generate UCSS dans LiteSpeed Cache). Cette fonction génère un CSS distinct pour chaque URL (WP Rocket l'injecte inline dans le HTML) et ne conserve que les règles détectées sur la page pendant son chargement. Un élément modifié ultérieurement par un script (menu déroulant, slider) peut alors perdre ses styles. WP Rocket consacre un guide entier aux problèmes d'affichage que cela engendre. Le jeu n'en vaut pas la chandelle : allégez et combinez vous-même les feuilles de style. C'est plus de travail, mais c'est largement rentabilisé.
De nombreuses extensions chargent leur CSS sur chaque page, y compris là où elles ne servent à rien : Contact Form 7 sur des pages sans formulaire, WooCommerce en dehors de la boutique. Chaque feuille de style injectée par WordPress possède un id tel que contact-form-7-css : la partie située avant -css constitue le handle à utiliser pour la retirer là où elle est inutile :
add_action( 'wp_enqueue_scripts', function () {
if ( ! is_page( 'contact' ) ) {
wp_dequeue_style( 'contact-form-7' );
}
}, 20 ); WooCommerce dispose de son propre filtre pour ses trois feuilles de style, woocommerce_enqueue_styles. Pour vos propres scripts, WordPress 6.3 et ses versions ultérieures peuvent ajouter defer :
wp_enqueue_script( 'acme-gallery', get_stylesheet_directory_uri() . '/js/gallery.min.js', array( 'jquery' ), '2.3.0', array( 'strategy' => 'defer' ) ); WordPress retire cet attribut defer, sans avertissement, dès qu'un script dépendant du vôtre reste bloquant ou qu'un script inline est ajouté après lui. Vérifiez la balise script dans le code source de la page.
Ne différez jQuery qu'avec un outil capable de gérer aussi les appels inline jQuery(...). WordPress enregistre jQuery sans defer : il bloque donc le head dès qu'un élément en dépend, et ajouter defer manuellement casse tous les appels inline jQuery(...) exécutés avant lui. L'option Load JavaScript deferred de WP Rocket diffère jQuery et encapsule ces appels inline. Defer JavaScript dans Perfmatters exclut jQuery tant que vous n'activez pas Include jQuery ; si vous l'activez, parcourez la page (menu, galerie, panier) pour vérifier que rien n'est cassé.
Un thème enfant dont le fichier style.css commence par @import url("../storefront/style.css") crée une chaîne d'@import. Supprimez cette ligne et chargez la feuille de style parente avec wp_enqueue_style.
Shopify
Les applications ajoutent leurs fichiers via les app embeds (Boutique en ligne, Modifier le thème, App embeds). Le script d'un embed se charge en async (sauf si son Liquid génère sa propre balise script), mais sa feuille de style bloque le rendu. Désactivez les embeds inutilisés et, après avoir désinstallé une application, cherchez dans theme.liquid et les snippets le code résiduel.
Les thèmes chargent leur CSS avec le filtre stylesheet_tag dans theme.liquid, ce qui génère un lien bloquant. Pour l'unique feuille de style de base, ce n'est pas un problème. En revanche, le filtre script_tag génère un script sans defer : écrivez cette balise vous-même :
<!-- bloque le premier affichage -->
{{ 'gallery.js' | asset_url | script_tag }}
<!-- ne le bloque pas -->
<script src="{{ 'gallery.js' | asset_url }}" defer></script> Shopify envoie déjà des 103 Early Hints pour un maximum de 10 fichiers render-blocking dans le head : ces fichiers démarrent donc tôt de toute façon. Ce sur quoi vous pouvez agir, c'est leur nombre et leur poids. Attendez-vous à ce que la feuille de style du checkout accéléré reste dans la liste (voir plus bas).
Next.js
Dans l'App Router, chaque import CSS devient une balise link de feuille de style tout en haut du head, et React n'affiche rien tant qu'elle n'est pas chargée. Next.js les regroupe en quelques chunks : la solution consiste donc à réduire le CSS. Déplacez le CSS propre à certaines routes hors du CSS global vers des CSS Modules : le CSS global importé dans le root layout est envoyé à chaque route, tandis qu'un CSS Module n'est chargé que par les routes qui l'importent. En savoir plus sur la façon dont Next.js génère ses fichiers CSS.
Next.js charge ses propres scripts en async ou en différé. Un script bloquant sur un site Next.js provient généralement d'un ajout manuel dans le layout. Chargez-le avec next/script, qui par défaut ne le charge qu'une fois que Next.js a commencé l'hydratation de la page :
import Script from 'next/script'
<Script src="https://example.com/widget.js" strategy="afterInteractive" /> Google Fonts et autres domaines
Le lien Google Fonts est une feuille de style bloquante hébergée sur fonts.googleapis.com, et les fichiers de polices proviennent d'un second domaine, fonts.gstatic.com. Lighthouse a attribué à ce fichier de 0,5 ko la valeur Duration la plus longue : il prend en compte la nouvelle connexion. Hébergez les polices vous-même et intégrez les règles @font-face dans votre propre feuille de style : la requête et les deux connexions disparaissent. Sur Next.js, next/font s'en charge déjà.
Outils de consentement, tests A/B et autres fichiers à ne pas toucher
- Un outil de consentement avec auto-blocking (Cookiebot, OtAutoBlock d'OneTrust, l'autobloqueur d'Usercentrics) : il doit s'exécuter avant tous les autres scripts pour les intercepter, il est donc synchrone par conception. L'alternative est le mode manuel, où vous balisez vous-même chaque script posant des cookies. Savoir si le jeu en vaut la chandelle est avant tout une question juridique. Un preconnect vers le domaine de l'outil permet au moins d'initier la connexion plus tôt.
- Un snippet d'A/B testing (Optimizely, AB Tasty, Convert) : synchrone à dessein, pour éviter que les visiteurs ne voient clignoter la version originale avant la variante. Retirez-le lorsqu'aucun test n'est en cours.
- Le content_for_header de Shopify : chaque thème en a besoin et vous ne pouvez pas le modifier. Sur les cinq boutiques testées pour cet article, il a ajouté une feuille de style bloquante pour le checkout accéléré, accelerated-checkout-backwards-compat.css. Laissez-le.
Alléger et combiner le CSS
Limitez le CSS render-blocking à quelques feuilles de style, chacune sous la barre des 15 ko compressés. 15 ko correspondent à peu près à ce qu'une nouvelle connexion transmet lors de son premier aller-retour.

Six feuilles de style render-blocking en Slow 4G dans le panneau Network de DevTools. Le vert représente l'attente du premier octet, identique pour chaque fichier. Le bleu correspond au téléchargement, qui augmente avec la taille du fichier.
- Combinez les minuscules fichiers ajoutés par votre thème et vos extensions. Chaque feuille de style attend un aller-retour complet avant l'arrivée de son premier octet, soit environ 0,6 s en Slow 4G, quelle que soit sa taille. Un fichier de 0,3 ko subit toute cette attente pour presque rien.
- Allégez ou découpez un fichier volumineux. Après la même attente, le fichier de 14 ko était chargé 0,4 s plus tard. Le fichier de 60 ko a nécessité une seconde de téléchargement supplémentaire, et la page est restée blanche jusqu'à son arrivée.
- Supprimez les règles inutilisées par la page. L'onglet Coverage de DevTools indique pour chaque fichier la part de CSS que la page n'utilise jamais. Sur le site médian, ce taux atteint 89 % (State of CWV, couverture mesurée par Chrome sur la page d'accueil).
- Ne mettez pas tout le CSS dans un seul gros fichier. L'ensemble du CSS, non allégé, réuni dans un unique fichier de 68 ko a affiché la page plus tard que les neuf fichiers séparés. Le gros fichier a partagé la bande passante avec les scripts différés et l'image hero, alors qu'avec neuf fichiers, les requêtes render-blocking s'accaparaient l'essentiel du débit.
- N'inlinez pas le CSS. Le CSS inline est injecté dans le HTML, et le HTML est le tout premier fichier dont le navigateur a besoin : tout le reste l'attend. L'inlining alourdit et ralentit donc le seul fichier que tout le monde attend. Plus grave encore, le navigateur ne peut généralement pas mettre le HTML en cache : chaque page vue télécharge donc à nouveau ce CSS, alors qu'une feuille de style séparée est mise en cache dès la première page. Parmi les sites ayant un TTFB sous les 900 ms et une à cinq requêtes bloquantes, 95,9 % de ceux sans CSS inline ont un bon FCP, contre 90,8 % pour ceux qui inlinent plus de 300 ko (State of CWV).
- Ne séparez pas « le reste » du CSS pour le charger plus tard. La vieille astuce du
media="print"ne fonctionne que pour le CSS qui n'apparaît jamais sur le premier écran, ce qui est rarement prévisible pour chaque page et chaque taille d'écran : trompez-vous, et la page s'affichera d'abord sans aucun style.
Remplacer chaque @import
Donnez à chaque fichier importé son propre lien dans le HTML, ou combinez-le dans la feuille de style parente. La suppression de l'@import sur la page produit a avancé le premier affichage de 137 ms une fois les scripts différés. Avec les scripts encore bloquants, le gain n'était que de 33 ms : jQuery arrivant à peu près en même temps que la feuille de style importée, l'affichage attendait jQuery de toute façon.
Différer les scripts
Ajoutez defer à chaque script du head dont le premier affichage n'a pas besoin. Les scripts modules sont déjà différés par défaut. L'attribut async retire également un script de la liste, mais il peut tout de même s'exécuter avant le premier affichage et bloquer le main thread : defer constitue donc un meilleur choix par défaut. Les scripts représentent aujourd'hui la part mineure de cet insight : différer les deux scripts n'a fait gagner que 24 ms, car le CSS s'est terminé plus tard de toute façon. Pour aller plus loin : async vs defer, JavaScript dans le head vs le footer et 14 méthodes pour différer JavaScript.
Démarrer la feuille de style principale plus tôt avec les 103 Early Hints
Grâce aux 103 Early Hints, le serveur indique au navigateur quels fichiers récupérer pendant qu'il génère encore le HTML. Envoyez un hint pour votre feuille de style principale :
HTTP/2 103
link: </css/main.min.css>; rel=preload; as=style L'intérêt est réel lorsque votre serveur met du temps à construire la page. La feuille de style se télécharge pendant ce temps : le gain équivaut donc au maximum au think time de votre serveur, et une page servie depuis le cache d'un CDN n'y gagne presque rien. Cloudflare propose une option dédiée (Speed, Settings, Content Optimization) et génère les hints à partir des en-têtes Link renvoyés par votre serveur. Apache 2.4.58 et ses versions ultérieures disposent de H2EarlyHint.
Vérifiez le LCP par la suite. Lorsque le CSS arrive plus tôt, les polices qu'il déclare démarrent plus tôt elles aussi : sur la page produit, la police Font Awesome de 156 ko a monopolisé de la bande passante au détriment de la photo du produit, retardant le LCP. Lighthouse conserve quoi qu'il en soit le fichier préchargé dans sa liste, avec 0,0 Kio. Pour en savoir plus : 103 Early Hints, et pourquoi un simple preload pour une feuille de style déjà liée n'aide pas.
Éviter fetchpriority="low" sur une feuille de style
Une recommandation courante consiste à appliquer fetchpriority="low" au CSS dont le premier écran n'a pas besoin. C'est un anti-pattern. Dans le head, Chrome ne rétrograde cette feuille de style que d'un cran, de la priorité highest à high, et continue de l'attendre avant le premier affichage. Dans sa simulation, Lighthouse détermine ce qui est bloquant en fonction de la priorité : il traite donc le fichier comme s'il avait disparu, sans Duration, affichant un FCP simulé plus rapide.
Je l'ai configuré sur quatre feuilles de style. Avec le bridage simulé, Lighthouse a fait passer le FCP de 2,0 s à 1,60 s et a augmenté le score de 96 à 97. Dans Chrome, le premier affichage est passé de 2 122 ms à 2 114 ms : vos visiteurs attendent donc tout autant qu'avant.

Lighthouse, bridage simulé

Chrome sur mobile, même page
Au moment indiqué par Lighthouse pour le FCP, Chrome affiche toujours un écran blanc.
Comment vérifier que la correction a fonctionné ?
Relancez Lighthouse sur mobile. Avec la correction, le score est passé de 96 à 100 et le FCP simulé de 2,0 s à 1,1 s. L'insight est passé du rouge avec douze fichiers à l'orange avec un seul : la feuille de style de 6,6 ko.

Avant

Après
Lighthouse 13.5.0, mobile, bridage simulé.
Lancez trois tests et retenez le résultat médian : sur la même page, le FCP simulé a varié de 1,5 s d'un test à l'autre.
CoreDash affiche le FCP et le LCP render delay dès les visites suivantes. CrUX et la Search Console reflètent les 28 derniers jours : deux semaines après la correction, la moitié de leurs données correspond donc encore à l'ancien site.
Vous voulez savoir si le CSS bloquant maintient votre FCP ou votre LCP mobile dans le rouge ? Lors d'une Core Web Vitals power hour, nous ouvrons ensemble vos field data et une trace de votre page, et vous repartez avec les fichiers à alléger, combiner ou différer.
Trouvez ce qui est vraiment lent.
Je remonte votre critical rendering path avec de vraies données terrain. Vous repartez avec une liste de fix priorisés, pas un rapport Lighthouse.
Demander l'audit