« Réduire le CSS inutilisé » est l’une des suggestions que Lighthouse affiche le plus souvent, en particulier sur les sites WordPress construits avec des thèmes multi-usages et des page builders. Le chiffre qui accompagne la suggestion est éloquent : des dizaines, voire des centaines de kilo-octets de règles que la page télécharge sans les utiliser. La tentation de corriger cela en un clic est forte, et de nombreux plugins d’optimisation proposent exactement cela : une fonction qui analyse la page, supprime tout ce qui n’est pas nécessaire et sert une feuille de style réduite au strict minimum.
Cela fonctionne, tant que l’utilisateur ne touche à rien. Le CSS « inutilisé » au moment de l’analyse est souvent simplement du CSS qui n’est pas encore utilisé : celui du menu ouvert, du message d’erreur d’un formulaire, de l’onglet sélectionné, du panier qui glisse depuis le côté. Dans cet article, nous voyons pourquoi le CSS pèse sur la performance, comment fonctionne la suppression automatique et pourquoi les états dynamiques en sont le point faible.
Pourquoi le CSS pèse sur la performance
Le CSS est une ressource qui bloque le rendu : tant que le navigateur n’a pas téléchargé et traité les feuilles de style du <head>, il n’affiche rien à l’écran. Chaque kilo-octet supplémentaire allonge le téléchargement, et chaque règle supplémentaire augmente le travail nécessaire pour construire le modèle de styles et calculer l’apparence de chaque élément. Sur un smartphone milieu de gamme, avec une connexion mobile, la différence entre 40 et 400 kilo-octets de CSS se voit directement dans le FCP et le LCP.
Le panneau Couverture de Chrome DevTools montre quelle part des feuilles de style est réellement appliquée à la page. Sur un site basé sur un thème multi-usage, il n’est pas rare que 80 ou 90 % du CSS ressorte comme inutilisé : des styles pour des composants jamais utilisés, des variantes pour des dizaines de mises en page, des règles de plugins chargées sur chaque page alors qu’elles ne servent que sur une seule.
Comment fonctionne la suppression automatique
Les outils qui génèrent le CSS « utilisé » suivent presque toujours le même schéma. Un navigateur headless charge la page, observe quels sélecteurs correspondent à des éléments présents dans le document et produit une feuille de style qui ne contient que ceux-là. Le résultat est inséré dans la page à la place des feuilles de style d’origine, qui, selon la configuration, sont supprimées, chargées de façon asynchrone ou chargées seulement à la première interaction.
La limite tient au concept même d’« utilisé » : l’analyse prend un instantané de la page à un seul moment, dans un seul état, souvent à une seule largeur d’écran. Tout ce qui n’existe pas dans le document à cet instant est considéré comme superflu.
Les outils les plus avancés conservent quand même les pseudo-classes comme :hover, :focus ou :checked, car ils peuvent vérifier que le sélecteur de base correspond à un élément. Ce qu’ils ne peuvent pas savoir, c’est quelles classes le JavaScript ajoutera plus tard, ou quels éléments seront insérés dans le document après le chargement : pour eux, ce qui n’existe pas à l’instant de l’analyse n’existera jamais.
Le problème des états dynamiques
Une page moderne n’est pas un document statique. Le JavaScript ajoute et retire des classes en réponse à ce que fait l’utilisateur, et chacune de ces classes a ses propres règles de style. Un exemple typique est le menu mobile :
/* CSS du thème */
.mobile-nav { display: none; }
.menu-open .mobile-nav { display: block; position: fixed; inset: 0; }
/* JavaScript du thème */
toggle.addEventListener( 'click', () => {
document.body.classList.toggle( 'menu-open' );
} );
Au moment de l’analyse, le body n’a pas la classe menu-open : la seconde règle ne correspond à rien et est supprimée. Le résultat, pour l’utilisateur, est un menu qui, au toucher, apparaît comme une liste de liens sans style par-dessus le contenu, ou n’apparaît pas du tout. La même chose se produit dans des dizaines de situations courantes :
- les en-têtes qui deviennent compacts et fixes après le défilement ;
- les onglets, accordéons et sliders avec la classe de l’élément actif ;
- les fenêtres modales, les popups promotionnels et les bandeaux de consentement aux cookies ;
- le mini-panier latéral, les avis d’ajout de produit, les messages WooCommerce ;
- les états d’erreur et de confirmation des formulaires, les champs obligatoires mis en évidence ;
- les variantes visibles uniquement par les utilisateurs connectés ou par ceux qui ont déjà des produits dans leur panier.
À cela s’ajoutent les différences entre modèles de page, comme une fiche produit avec variantes par rapport à une fiche sans, et entre largeurs d’écran, quand l’analyse s’exécute à une seule résolution. Ce sont précisément les points où l’utilisateur est sur le point de faire quelque chose d’important : ouvrir le menu, choisir une taille, remplir un formulaire, accéder au panier.
La safelist : un correctif qui demande de l’entretien
Pour limiter les dégâts, les outils de suppression permettent d’indiquer une safelist : une liste de sélecteurs, ou de parties de sélecteurs, à toujours conserver. C’est une solution nécessaire mais fragile. Quelqu’un doit connaître toutes les classes dynamiques utilisées par le thème, les plugins et les scripts tiers, et mettre la liste à jour à chaque changement. Une mise à jour du thème qui renomme une classe, un nouveau plugin qui introduit son propre popup, une campagne qui active un autre bandeau : chaque changement peut rouvrir le problème sans que personne ne s’en aperçoive, car les tests de performance automatisés continuent d’afficher l’état initial, qui est parfait.
Il y a aussi un coût opérationnel. Le CSS réduit doit être généré pour chaque page ou modèle, stocké et régénéré quand les contenus ou les styles changent. Si la régénération n’a pas lieu, ou a lieu trop tard, la page est servie avec une feuille de style qui ne correspond plus au balisage, avec des erreurs visibles qu’il est difficile de rattacher à leur cause.
Quand les feuilles de style d’origine arrivent plus tard
De nombreuses configurations cherchent un compromis : elles servent tout de suite le CSS réduit et chargent les feuilles de style complètes de façon asynchrone, ou à la première interaction. C’est plus sûr qu’une suppression totale, car toutes les règles finissent par arriver. Mais cela déplace le problème vers d’autres métriques. Si les feuilles de style complètes arrivent alors que l’utilisateur est déjà en train de lire, des éléments peuvent changer de taille ou de position, avec des décalages de mise en page qui dégradent le CLS. Si elles arrivent à la première interaction, le premier toucher doit aussi attendre que les styles soient téléchargés et appliqués, avec des effets sur l’INP. C’est le même schéma que pour le delay du JavaScript : le coût ne disparaît pas, il change de moment.
Le Critical CSS, c’est-à-dire l’intégration dans la page des seuls styles nécessaires à la partie visible au chargement, suivie de la feuille de style complète non bloquante, suit la même logique et présente les mêmes risques si le style critique est incomplet. Il fonctionne bien quand il est généré et vérifié pour chaque modèle de page, mal quand il est généré une fois puis oublié.
Réduire le CSS à la source
L’approche la plus robuste consiste à empêcher le CSS superflu d’arriver dans la page, plutôt que de le supprimer après l’avoir généré. En pratique, cela signifie :
- Séparer les styles par modèle de page. Les styles de la page d’accueil, des articles, des fiches produit et du tunnel de commande vont dans des fichiers distincts, chargés uniquement là où ils sont nécessaires. Ce site fonctionne lui aussi ainsi : les styles des sections de la page d’accueil ne sont jamais chargés sur les pages du blog, et inversement.
- Charger les styles des blocs seulement s’ils sont présents. WordPress, avec les thèmes à blocs, peut n’inclure le CSS de chaque bloc que sur les pages qui le contiennent.
- Désactiver les styles des plugins là où ils ne sont pas nécessaires. La feuille de style du formulaire de contact n’a aucune raison d’être chargée sur chaque page du site, ni celle du slider sur les pages sans slider.
- Nettoyer au moment du développement, pas à l’exécution. Des outils comme PurgeCSS peuvent supprimer les règles inutilisées pendant le build, en analysant les modèles et les scripts avec une safelist versionnée avec le code et vérifiée par des tests, au lieu d’un instantané de la page en production.
- Évaluer le poids du thème et du page builder. Quand l’essentiel du CSS appartient à des fonctionnalités que le site n’utilise pas, la solution durable est un thème plus léger, pas un outil qui masque son poids.
Comment vérifier que rien n’est cassé
Quelle que soit la stratégie choisie, la vérification doit porter sur les états, pas seulement sur la page tout juste chargée. Le panneau Couverture peut enregistrer l’utilisation du CSS pendant que vous interagissez avec la page : en ouvrant le menu, en sélectionnant une variante et en envoyant un formulaire vide, vous voyez la part de règles utilisées augmenter, et il devient clair que beaucoup de CSS « inutilisé » ne faisait qu’attendre.
Pour les sites où la continuité compte, il vaut la peine d’automatiser le contrôle avec des tests de régression visuelle qui capturent les principaux états : menu ouvert sur mobile, panier avec des produits, formulaire avec des erreurs, bandeau de consentement, chacun aux largeurs les plus utilisées. Et après toute modification de la gestion du CSS, surveillez l’évolution du CLS et de l’INP, en plus du LCP, dans les données d’utilisateurs réels.
En résumé
Le CSS inutilisé est un vrai problème, car il bloque le rendu et ralentit le premier affichage de la page. La suppression automatique s’y attaque en prenant un instantané de la page dans un seul état, et pour cette raison elle supprime aussi les règles des menus, des formulaires, des paniers et des composants interactifs que l’utilisateur rencontrera un instant plus tard. Les safelists et le chargement différé limitent les dégâts, mais demandent un entretien continu et déplacent le coût vers le CLS et l’INP.
Chaque raccourci a un coût à mesurer. Le moyen le plus fiable d’avoir peu de CSS, c’est de ne pas charger de CSS superflu au départ : des styles séparés par modèle de page, chargés uniquement là où ils sont nécessaires, nettoyés au moment du développement et vérifiés sur tous les états qui comptent pour l’utilisateur et pour l’entreprise.