Pourquoi mon critical CSS a-t-il cassé mon menu / overlay (il s'affiche ouvert au chargement) ?
En une phrase : les générateurs de critical CSS ne conservent que les styles de ce qui est visible en haut de page au chargement. Vos éléments masqués par défaut et ouverts au clic (menu mobile, overlay de recherche, modale, panneau latéral) sont jugés inutiles et supprimés. Résultat : au chargement, ils s'affichent ouverts, cassés, sans style.
Vous activez le critical CSS (qui se contente d'injecter les styles pour le premier rendu) ou l'option « Remove unused CSS » pour gagner des points sur PageSpeed. Le score grimpe. Et soudain : votre overlay de recherche s'affiche grand ouvert au chargement, votre menu mobile se déplie, un bouton récupère sa vilaine bordure grise par défaut. Vous rechargez, videz le cache… rien n'y fait.
Le plus déroutant : quand vous inspectez le code, la règle CSS est bien là dans le HTML. Mais le navigateur ne l'applique pas. Voici l'explication complète, et le correctif qui tient dans la durée.
Ce que fait vraiment un générateur de critical CSS
L'idée du critical CSS est légitime et efficace : plutôt que de charger toute votre feuille de styles avant le premier rendu (ce qui bloque l'affichage), vous en extrayez uniquement le CSS nécessaire au haut de page visible, vous l'insérez en ligne dans le <head>, et chargez le reste plus tard (defer).
Pour décider de ce qui est « nécessaire », l'outil restitue la page et observe ce qui est visible dans le viewport au moment du chargement. Tout ce qui n'est pas visible à cet instant est considéré comme non critique, ou, en mode « Remove unused CSS », carrément comme inutile et supprimable.
Et c'est là que se cache le piège.
La vraie cause : « masqué par défaut » = « jugé inutile »
Repensez à l'état de vos composants interactifs au chargement de la page :
- le menu mobile : fermé (
display:noneoutransformhors écran) ; - l'overlay de recherche : masqué (
opacity:0; visibility:hidden) ; - la modale, le panneau latéral, le méga-menu : masqués ;
- repliés, les onglets et accordéons : contenu masqué.
Tous ces éléments sont invisibles au moment où le générateur observe la page. Il en conclut, logiquement mais à tort, que leur style est inutile, et le retire du critical CSS.
Le problème : ces éléments sont censés apparaître plus tard, au clic, via JavaScript. Mais leur style a disparu. Deux symptômes classiques :
Ce qui casse
La règle qui les masquait a disparu. Un
.overlay { opacity:0; visibility:hidden }supprimé → plus rien ne masque l'overlay → il s'affiche ouvert au chargement.La règle d'apparence a disparu. Un
button { border:0; background:none }non conservé → le bouton retrouve le style par défaut du navigateur (bordure grise, remplissage système).
Le symptôme qui rend fou : « la règle est là, mais ignorée »
C'est le point qui coûte des heures. Vous inspectez, vous voyez clairement .overlay { visibility:hidden } quelque part dans le HTML minifié. Alors pourquoi le navigateur ne l'applique-t-il pas ?
Parce que dans un pipeline de critical CSS, il existe deux feuilles de style :
- le critical inline (dans le
<head>, appliqué immédiatement), amputé de vos règles interactives ; - la feuille complète, censée arriver en différé.
Trois choses tournent mal, souvent en même temps :
- La feuille complète arrive trop tard (après que le JS a déjà tenté d'ouvrir/fermer l'élément), voire jamais sur certains chemins de rendu.
- En mode « Remove unused CSS », la règle a été retirée des DEUX feuilles : elle n'existe plus nulle part.
- La cascade se retourne contre vous : une règle présente mais moins spécifique (ou chargée après) perd face au style inline ou par défaut.
Donc « la règle est dans le HTML » ne signifie pas « la règle l'emporte ». Elle peut être présente et perdante face à la cascade, ou présente dans une feuille pas encore chargée au moment critique.
Les pièges du diagnostic (pourquoi vider le cache ne suffit pas)
Avant de corriger, il faut observer le rendu réel, et là, trois pièges vous attendent :
- Caches mobile et desktop séparés. De nombreux moteurs génèrent un critical CSS différent pour mobile et desktop. Vous corrigez, vous testez sur desktop, tout va bien… mais le cache mobile sert toujours l'ancienne version cassée. Testez et « préchauffez » les deux, avec le bon User-Agent (l'identifiant envoyé par le navigateur pour signaler s'il est mobile ou desktop).
- « Vider le cache » ne vide pas toujours le critical CSS par page. Le critical est souvent stocké par URL, séparément du cache HTML. Un « clear all » peut laisser en place des fichiers critical obsolètes. Il faut cibler explicitement le CSS généré.
- Le critical dérive d'une source mise en cache. S'il est régénéré à partir d'une version obsolète de votre feuille de style source, votre correctif n'apparaît jamais. Il faut forcer la régénération depuis la source à jour.
Pour voir le rendu réel sans être trompé par le cache : ajoutez un paramètre bidon à l'URL (?cb=123) pour forcer un rendu neuf, et comparez avec l'URL normale.
Le correctif qui tient dans la durée (et voyage avec votre thème)
La tentation, c'est de mettre les sélecteurs dans une « safelist » (liste d'exclusion) du plugin. Ça marche… tant que vous gardez ce plugin, avec cette config. Le jour où vous changez d'outil ou reconstruisez le site, ça recasse.
Le correctif robuste et portable consiste à sortir vos règles vraiment critiques du CSS optimisable, et à les insérer vous-même en ligne, de manière protégée :
a. Identifier les règles « à ne jamais toucher »
- l'état masqué par défaut de chaque élément interactif (
display:none,opacity:0; visibility:hidden…) ; - le reset des boutons/contrôles (
border:0; background:none…) ; - le style complet de l'élément une fois ouvert (pour qu'il soit correct dès la toute première ouverture) ;
- rendez ces composants autonomes : un bouton doit porter son propre style, sans dépendre d'une classe utilitaire elle-même susceptible d'être optimisée.
b. Insérez-les en ligne après le rendu du head
Placez ces règles dans un <style> bloc après l'appel qui génère le <head> (en WordPress : après wp_head(), typiquement dans header.php). Ainsi, elles arrivent en dernier et l'emportent dans la cascade sur le critical inséré plus haut.
c. Marquez le bloc comme non optimisable
Indiquez au moteur d'optimisation de ne pas y toucher. La plupart respectent des attributs dédiés :
<style data-no-optimize="1" data-no-minify="1" data-no-defer="1">
/* hidden state + button reset + full overlay style, hard-coded values */
.search-overlay { opacity: 0; visibility: hidden; /* ... */ }
.search-overlay.is-open { opacity: 1; visibility: visible; }
.search-toggle { border: 0; background: none; color: #1a1a1a; }
</style>d. Codez les valeurs en dur
N'utilisez pas de variables CSS (var(--gold)) dans ce bloc : si votre :root passe elle-même par l'optimiseur, la variable peut se retrouver non définie et votre style s'effondre. Codez la couleur en dur.
Avantage décisif : ce correctif vit dans le thème. Il fonctionne avec l'optimiseur, sans l'optimiseur, et survit à un changement d'outil.
Là où Mantys Core fait la différence
Tout moteur de critical CSS fait face à ce dilemme : il ne peut pas deviner qu'un élément masqué sera ouvert au clic. La vraie question n'est donc pas « est-ce que ça arrive ? » (ça arrive avec tous), mais « l'outil vous donne-t-il des leviers propres pour le gérer ? ».
Mantys Core est conçu pour ça :
il respecte les blocs marqués
data-no-optimize/data-no-minify/data-no-defer(exactement le mécanisme de correctif portable décrit plus haut) et traite son propre bloc critical de la même façon ;il vous permet de cibler la régénération du critical page par page, depuis la source à jour, sans être piégé par un critical obsolète ;
et il gère explicitement le découpage mobile / desktop au lieu de vous laisser deviner quel cache sert quoi.
Autrement dit : il fait le gros du travail d'allègement, tout en vous laissant un contrôle chirurgical sur les composants interactifs, au lieu de tout dénuder et de vous laisser réparer.
En résumé
- Le critical CSS ne conserve que le style de ce qui est visible au chargement. Vos éléments masqués par défaut (menu, overlay, modale) sont jugés inutiles et supprimés.
- Symptôme trompeur : la règle est dans le HTML mais ignorée : deux feuilles, une cascade qui se retourne, ou une simple suppression.
- Diagnostic : méfiez-vous des caches mobile/desktop séparés, du critical par URL que le « clear all » ne purge pas, et de la source obsolète.
- Correctif durable : insérez en ligne l'état masqué + style complet des composants interactifs, après
wp_head(), dans un bloc non optimisable, avec des valeurs codées en dur. Il voyage avec le thème.