# CSS critique sur WordPress : générer, injecter et charger le reste en différé

> Générez le CSS critique par template, injectez-le dans le head et différez la feuille principale pour éliminer le flash de contenu sans style.

- Auteur : Clément Hadrot
- Publié le : 2020-01-15
- Mis à jour le : 2020-01-15
- Catégorie : Performance
- URL : https://wpmoderne.dev.wordpress-developpement.fr/performance/css-critique-wordpress-generer-injecter-differe/

## L’essentiel

- Un CSS critique par gabarit, pas un seul pour tout le site
- Injection inline, jamais via une requête bloquante
- Chargement différé sans provoquer de FOUC

Un client nous a envoyé une capture d'écran un peu paniquée : sa page d'accueil affichait pendant une fraction de seconde un mur de texte sans mise en forme, avant que tout se stabilise d'un coup. Ce phénomène a un nom, le FOUC (flash of unstyled content), et il vient presque toujours de la même cause : le navigateur bloque le rendu tant qu'il n'a pas téléchargé et parsé la feuille de style principale.

La solution consiste à extraire uniquement les règles nécessaires à l'affichage de ce qui est visible sans défiler (le fameux « above the fold »), à les injecter directement dans le `<head>`, puis à charger le reste du CSS sans bloquer le rendu. Voici comment le mettre en place proprement sur un thème WordPress classique, gabarit par gabarit.

## Étape 1 : identifier les gabarits qui comptent

Il est tentant de vouloir un seul CSS critique « générique » pour tout le site. C'est une erreur : la page d'accueil, une fiche produit et un article de blog n'affichent pas le même contenu au-dessus de la ligne de flottaison. Commencez par lister vos gabarits réels : `front-page.php`, `single.php`, `page.php`, `archive.php`, et éventuellement une fiche produit WooCommerce si le site en propose.

Pour chaque gabarit, prévoyez un fichier de CSS critique distinct, par exemple `critical-front.css`, `critical-single.css`, etc. C'est plus de travail à la mise en place, mais c'est la seule approche qui tienne dans la durée.

## Étape 2 : générer le CSS critique

Plusieurs outils en ligne de commande font ce travail en rendant la page dans un navigateur headless et en relevant les règles réellement appliquées à la zone visible. Le principe reste le même quel que soit l'outil choisi :

```
npx critical https://exemple-client.test/ \
  --base ./dist/ \
  --css ./dist/style.css \
  --width 1280 --height 720 \
  --target critical-front.css
```

Il faut générer une version par largeur d'écran significative (mobile et desktop au minimum), car les éléments visibles sans défiler ne sont pas les mêmes. Dans la pratique, deux CSS critiques par gabarit (mobile-first, puis un ajustement desktop) suffisent dans la grande majorité des cas.

> L'essentiel à retenir : Un CSS critique par gabarit, pas un seul pour tout le site ; Injection inline, jamais via une requête bloquante ; Chargement différé sans provoquer de FOUC

## Étape 3 : injecter le CSS critique dans le head

Le CSS critique doit être **inline**, jamais chargé via une balise `<link>` classique, sinon vous réintroduisez exactement le problème que vous cherchez à résoudre. Sur WordPress, on accroche cette injection à `wp_head` avec une priorité basse pour qu'elle arrive tôt :

```
function wpm_inline_critical_css() {
    $template = wpm_get_current_template_slug();
    $path = get_stylesheet_directory() . "/critical/{$template}.css";

    if ( file_exists( $path ) ) {
        echo '<style id="wpm-critical">' . file_get_contents( $path ) . '</style>';
    }
}
add_action( 'wp_head', 'wpm_inline_critical_css', 1 );
```

La fonction `wpm_get_current_template_slug` est à écrire selon votre logique de gabarits (elle peut simplement s'appuyer sur `is_front_page()`, `is_single()`, etc.). L'essentiel est que le fichier lu corresponde exactement à la page affichée.

## Étape 4 : différer la feuille de style principale

Une fois le CSS critique en place, la feuille complète doit être chargée sans bloquer le rendu. La technique la plus fiable reste le chargement en `media="print"` basculé en `media="all"` une fois chargé, avec un repli en `<noscript>` :

```
function wpm_defer_main_stylesheet( $html, $handle ) {
    if ( 'wpm-style' !== $handle ) {
        return $html;
    }
    $html = str_replace( "media='all'", "media='print' onload=\"this.media='all'\"", $html );
    $html .= "<noscript><link rel='stylesheet' href='" . esc_url( get_stylesheet_uri() ) . "'></noscript>";
    return $html;
}
add_filter( 'style_loader_tag', 'wpm_defer_main_stylesheet', 10, 2 );
```

Cette astuce fonctionne parce que la plupart des navigateurs téléchargent une feuille `print` à faible priorité sans bloquer le rendu de la page, puis exécutent `onload` pour la reclasser en `all` une fois disponible.

## Étape 5 : mesurer et invalider le cache au bon moment

Le CSS critique se périme dès qu'un thème change de version ou qu'un designer ajuste une marge dans la zone visible. Prévoyez une régénération dans votre pipeline de déploiement plutôt qu'à la main :

- Régénération automatique lors du build du thème, pas au moment du déploiement en production.
- Purge du cache de page WordPress après chaque mise à jour du CSS critique, sans quoi d'anciennes règles resteront servies.
- Vérification visuelle systématique : un CSS critique mal généré peut masquer un élément au lieu de simplement retarder son style.

> Un CSS critique qui n'est jamais régénéré est pire qu'absent : il finit par afficher une mise en page obsolète pendant la fraction de seconde où il agit seul.

## En résumé

Le CSS critique n'est pas une optimisation à activer une fois pour toutes : c'est un mécanisme à entretenir, gabarit par gabarit, à chaque évolution du thème. Bien fait, il élimine le FOUC et améliore nettement le First Contentful Paint. Mal entretenu, il devient une source de bugs visuels difficiles à diagnostiquer. Le jeu en vaut la chandelle dès que le site reçoit un trafic significatif sur sa page d'accueil ou ses pages de destination.
