vendredi 25 septembre 2026

À propos

Contact

Performance

Charger le JS et le CSS intelligemment sur WordPress avec defer et async

defer, async, script_loader_tag : le guide pratique pour arrêter de bloquer le rendu de vos pages WordPress avec des scripts mal chargés.

Par Clément Hadrot • 7 juillet 2022 • 6 min de lecture • Aucun commentaire
Charger le JS et le CSS intelligemment sur WordPress avec defer et async

Chaque script chargé de façon classique dans le <head> d’une page WordPress bloque le rendu : le navigateur doit le télécharger et l’exécuter avant de continuer à construire la page. Sur un site avec plusieurs plugins, chacun enregistrant son propre fichier JavaScript, cette accumulation peut faire grimper le temps de rendu de façon significative sans qu’aucun octet de PHP ne soit en cause.

Les attributs defer et async permettent de sortir ces scripts du chemin critique de rendu. Mais les deux ne sont pas interchangeables, et les appliquer sans discernement peut casser des scripts qui dépendent les uns des autres, à commencer par jQuery. Voici comment faire les choses proprement en WordPress 6.0.

Comprendre la différence entre defer et async

Sans attribut, un script est téléchargé et exécuté de façon synchrone, dans l’ordre où il apparaît dans le document, en bloquant le parsing du HTML pendant ce temps.

  • async télécharge le script en parallèle du parsing HTML, puis l’exécute dès qu’il est prêt, en interrompant le parsing à ce moment précis. L’ordre d’exécution entre plusieurs scripts async n’est pas garanti.
  • defer télécharge également le script en parallèle, mais reporte son exécution jusqu’à ce que le parsing HTML soit terminé, juste avant l’événement DOMContentLoaded. L’ordre d’exécution entre plusieurs scripts defer est, lui, garanti et respecte l’ordre du document.

Pour la grande majorité des scripts WordPress (widgets, animations, tracking non critique), defer est le choix le plus sûr : il préserve l’ordre de dépendance tout en libérant le rendu. async convient mieux à des scripts totalement indépendants, comme certains outils de mesure d’audience qui n’ont besoin d’aucun autre script pour fonctionner.

Pourquoi ne pas simplement passer un argument à wp_enqueue_script

À la date de cet article, WordPress est en version 6.0. La fonction wp_enqueue_script() ne propose pas encore de paramètre natif pour définir une stratégie de chargement : son cinquième argument reste un simple booléen ou tableau contrôlant la position du script (pied de page ou non) et, plus récemment, quelques options limitées. Il n’existe pas d’argument strategy permettant de demander defer ou async directement à l’enregistrement du script.

La méthode qui fonctionne aujourd’hui consiste donc à passer par le filtre script_loader_tag, qui permet de réécrire la balise <script> générée par WordPress avant qu’elle ne soit imprimée dans le HTML.

Ajouter defer avec le filtre script_loader_tag

Voici un exemple qui ajoute l’attribut defer à un script précis, identifié par son handle d’enregistrement :

function monsite_defer_script( $tag, $handle, $src ) {
    $scripts_a_differer = array( 'mon-script-animation', 'mon-script-carousel' );

    if ( in_array( $handle, $scripts_a_differer, true ) ) {
        return str_replace( ' src', ' defer src', $tag );
    }

    return $tag;
}
add_filter( 'script_loader_tag', 'monsite_defer_script', 10, 3 );
L'essentiel à retenir : defer et async ne se comportent pas du tout de la même façon ; jQuery doit rester chargé en priorité s'il est une dépendance ; script_loader_tag reste la méthode pour ajouter ces attributs en WP 6.0

Le principe est le même pour async :

function monsite_async_script( $tag, $handle, $src ) {
    if ( 'mon-script-analytics' === $handle ) {
        return str_replace( ' src', ' async src', $tag );
    }

    return $tag;
}
add_filter( 'script_loader_tag', 'monsite_async_script', 10, 3 );

Il est préférable de cibler explicitement les handles plutôt que d’appliquer defer à tous les scripts sans distinction. Une liste blanche évite les mauvaises surprises sur des scripts tiers ajoutés par des plugins dont on ne maîtrise pas le comportement.

Le piège de jQuery et des scripts qui en dépendent

jQuery est encore, en 2022, une dépendance de nombreux plugins WordPress et de nombreux thèmes, notamment via wp_enqueue_script() avec jquery déclaré dans le tableau des dépendances. Différer jQuery sans différer également tout ce qui en dépend casse immanquablement ces scripts : ils s’exécutent avant que jQuery ne soit défini dans l’espace global, provoquant des erreurs JavaScript silencieuses côté navigateur.

Conseil maison : avant de différer un script, ouvrez la console développeur et repérez ses dépendances via l’inspection du DOM ou, plus fiable, en listant les dépendances déclarées dans le code du plugin. Si jQuery est différé, tous ses dépendants doivent l’être aussi, dans le même ordre.

Concrètement, cela signifie que si vous différez jquery-core et jquery-migrate, il faut également différer chaque script qui les déclare en dépendance, faute de quoi vous obtiendrez des erreurs du type $ is not defined. La solution la plus sûre reste souvent de laisser jQuery se charger normalement et de ne différer que les scripts qui n’en dépendent pas, comme les scripts d’analytics ou les widgets autonomes en JavaScript natif.

Cas particulier du CSS : préchargement plutôt que defer

Le CSS n’a pas d’équivalent direct de defer, puisqu’un attribut defer sur une balise <link rel="stylesheet"> n’a aucun effet. Pour éviter qu’une feuille de style non critique ne bloque le rendu, la technique consiste à la charger en rel="preload" puis à basculer son rel vers stylesheet une fois le téléchargement terminé, via un petit script inline ou l’attribut onload :

function monsite_preload_style( $html, $handle, $href, $media ) {
    if ( 'mon-style-non-critique' === $handle ) {
        return '<link rel="preload" as="style" href="' . esc_url( $href ) . '" onload="this.onload=null;this.rel=\'stylesheet\'">';
    }

    return $html;
}
add_filter( 'style_loader_tag', 'monsite_preload_style', 10, 4 );

Vérifier le résultat sans casser le site

Avant de déployer ces changements en production, quelques vérifications s’imposent :

  1. Ouvrir la console développeur du navigateur et vérifier l’absence de nouvelles erreurs JavaScript.
  2. Tester chaque fonctionnalité interactive du site : menu mobile, formulaire de contact, carrousel, popin.
  3. Vérifier dans l’onglet réseau que les scripts différés portent bien l’attribut attendu dans le HTML source.
  4. Refaire un test de performance pour confirmer le gain sur le temps de rendu.

En résumé

Différer intelligemment le JavaScript reste, en WordPress 6.0, une opération manuelle qui passe par le filtre script_loader_tag, faute d’argument natif dans wp_enqueue_script(). La règle d’or : defer par défaut pour préserver l’ordre d’exécution, async réservé aux scripts totalement indépendants, et une vigilance particulière sur jQuery et ses dépendants pour ne pas casser le site en voulant l’accélérer.

Partager :

À propos de l'auteur

Clément Hadrot

Développeur WordPress, passionné par Elementor, le FSE et l’automatisation par IA.

Voir tous ses articles

Dans la même veine

À lire aussi