Back/forward cache : pourquoi le bouton Retour de votre site est lent

Le back/forward cache rend instantané le retour à la page précédente, mais beaucoup de sites en sont exclus sans le savoir : comment il fonctionne, ce qui le bloque, et comment le vérifier et le gérer.

Une fenêtre de navigateur avec le bouton Retour surligné en jaune et, à côté, une pile de pages conservées en mémoire qui reviennent à l’écran

Il y a un geste que les utilisateurs font tout le temps et que presque personne n’optimise : le bouton Retour. On ouvre une fiche produit depuis la liste, on revient à la liste ; on lit un article, on revient à l’accueil ; on consulte une page de livraison, on revient au panier. Sur mobile, où le balayage latéral ou le bouton système rend le retour en arrière encore plus naturel, une part importante des navigations est de ce type.

Tous les navigateurs modernes disposent d’un mécanisme qui rend ce geste instantané : le back/forward cache, souvent abrégé en bfcache. Quand il fonctionne, la page précédente réapparaît en quelques millisecondes, exactement comme elle était, avec la même position de défilement et les mêmes données dans les formulaires. Quand il ne fonctionne pas, le navigateur recharge tout depuis le début. Et sur beaucoup de sites, il ne fonctionne pas, pour des raisons que souvent personne n’a jamais vérifiées.

Ce qu’est le back/forward cache

Le bfcache n’est pas un cache HTTP et n’a rien à voir avec le cache de page du serveur. C’est une mémoire du navigateur où l’on conserve, dans son état vivant, toute la page qu’on vient de quitter : le DOM, l’état JavaScript, la position de défilement, les valeurs des formulaires. Quand l’utilisateur part, la page n’est pas détruite mais gelée : les minuteurs s’arrêtent, les scripts cessent de tourner, mais tout reste en mémoire. Si l’utilisateur revient assez vite, la page est dégelée et affichée immédiatement, sans requête au serveur et sans réexécuter le code.

La différence avec le cache HTTP est substantielle. Même avec toutes les ressources en cache, une navigation normale doit reconstruire la page : lire le HTML, appliquer les feuilles de style, exécuter les scripts, afficher. Avec le bfcache, ce travail est déjà fait et le résultat est simplement remis à l’écran.

Comparaison du bouton Retour : sans le bfcache, le navigateur fait une nouvelle requête, télécharge les ressources, exécute le JavaScript et réaffiche la page en 1,6 seconde, en perdant le défilement et les formulaires ; avec le bfcache, la page est restaurée depuis la mémoire en 0,03 seconde, avec le défilement et l’état intacts
Avec le bfcache, le retour à la page précédente ne demande ni réseau ni exécution de code.

Pourquoi c’est important pour les Core Web Vitals et pour le business

Les navigations arrière et avant ne sont pas un cas marginal : selon les données publiées par l’équipe Chrome, elles représentent environ une navigation sur dix sur ordinateur et environ une sur cinq sur mobile. Le Chrome UX Report les compte comme des visites à part entière, et distingue les types de navigation, y compris la part des navigations arrière/avant servies depuis le bfcache.

Une page restaurée depuis le bfcache a un LCP pratiquement nul, car le contenu est déjà visible dès la première image, et ne produit aucun décalage de mise en page lié au chargement. Si une page est exclue, chaque retour est un chargement complet, avec tout ce que cela implique pour le LCP, le CLS et l’INP. Rendre une page compatible avec le bfcache, c’est donc améliorer les données de terrain sur une part importante des visites sans toucher aux serveurs, aux images ou aux scripts : le chargement est supprimé purement et simplement.

En termes d’expérience, l’effet est encore plus évident. Pensez à un utilisateur qui fait défiler une longue liste de produits, ouvre une fiche produit et revient : avec le bfcache, il se retrouve exactement où il était, avec les filtres appliqués ; sans lui, il repart souvent du haut de la page, doit retrouver sa place et, si les filtres étaient gérés par JavaScript, les redéfinir. C’est une friction que les utilisateurs ne savent pas nommer mais qu’ils ressentent clairement, et elle se traduit par des sessions plus courtes et moins de produits consultés.

Pourquoi une page est exclue

Le navigateur ne garde une page dans le bfcache que s’il est sûr de pouvoir la geler et la dégeler sans effets indésirables. Certaines fonctionnalités de la page, ou des réponses du serveur, l’en empêchent. Les causes les plus fréquentes sont peu nombreuses, et presque toujours involontaires.

Tableau des causes d’exclusion du bfcache avec les remèdes : Cache-Control no-store sur le HTML, à réserver aux pages vraiment privées ; écouteurs de l’événement unload, à remplacer par pagehide ou visibilitychange ; connexions WebSocket ou WebRTC ouvertes, à fermer dans pagehide et à rouvrir dans pageshow ; transactions IndexedDB en cours ; window.opener pointant vers une autre page, à éviter avec rel noopener ; requêtes fetch non terminées
Les causes d’exclusion les plus courantes et le remède correspondant.

Cache-Control: no-store

L’en-tête Cache-Control: no-store sur le document HTML indique au navigateur que la page ne doit être conservée d’aucune façon. C’est pourquoi les navigateurs ont historiquement exclu du bfcache les pages qui l’envoient. Cela a du sens pour les contenus vraiment sensibles, comme l’espace d’un compte bancaire, mais il est courant de le trouver sur des pages publiques à cause de plugins, de configurations de serveur ou de règles copiées d’autres projets. Chrome introduit progressivement la possibilité d’utiliser le bfcache même avec no-store dans des conditions sûres, par exemple quand les cookies n’ont pas changé, mais il est imprudent d’y compter : l’en-tête ne devrait être utilisé que là où il est nécessaire.

Le cas de no-cache doit être distingué : il demande seulement de revalider la ressource avant de la réutiliser depuis le cache HTTP et n’empêche pas le bfcache. Qui veut éviter qu’une page soit servie depuis le cache du navigateur sans contrôle, mais n’a pas de besoin de confidentialité, devrait utiliser no-cache ou une durée de vie courte avec revalidation, comme nous l’avons vu en parlant de HTTP 304 Not Modified.

L’événement unload

L’événement unload est déclenché quand la page est détruite. Avec le bfcache, la page n’est pas détruite ; le navigateur ne peut donc pas garantir que le code associé sera exécuté : pour ne pas casser ce code, beaucoup de navigateurs excluent directement les pages qui l’utilisent. Chrome a commencé à retirer progressivement l’événement, mais de nombreux scripts d’analytics, widgets et plugins obsolètes l’utilisent encore. Le remplacement correct est l’événement pagehide, ou visibilitychange pour envoyer des données quand la page est masquée, qui fonctionnent avec et sans le bfcache.

// À éviter : exclut la page du bfcache
window.addEventListener( 'unload', inviaStatistiche );

// Correct : fonctionne aussi quand la page est gelée
document.addEventListener( 'visibilitychange', () => {
	if ( document.visibilityState === 'hidden' ) {
		inviaStatistiche();
	}
} );

L’événement beforeunload doit lui aussi être utilisé avec parcimonie : il a du sens pour avertir l’utilisateur qu’il est sur le point de perdre un formulaire non enregistré, et dans ce cas il vaut mieux l’ajouter seulement quand le formulaire a été modifié et le retirer après l’enregistrement, au lieu de le garder toujours actif.

Connexions ouvertes et autres cas

Une page avec une connexion WebSocket ou WebRTC ouverte, typique des chats en direct et de certains widgets d’assistance, ne peut pas être gelée sans interrompre la connexion, et les navigateurs ont tendance à l’exclure. Il en va de même pour les transactions IndexedDB en cours et, dans certains navigateurs, pour les requêtes réseau non terminées. Une page ouverte par une autre avec une référence window.opener active peut aussi être exclue : les liens vers d’autres fenêtres devraient utiliser rel="noopener", que les navigateurs modernes appliquent déjà par défaut aux liens avec target="_blank".

La solution pour les connexions est de les fermer quand la page est masquée et de les rouvrir quand elle redevient visible, avec les événements pagehide et pageshow. Beaucoup de fournisseurs de chats et de widgets ont mis à jour leurs scripts en conséquence ; pour les autres, un chargement différé jusqu’au premier clic, comme décrit dans l’article sur les scripts tiers, évite le problème pour toutes les visites où le widget n’est pas utilisé.

Comment vérifier si une page est compatible

Le contrôle le plus rapide se fait avec les DevTools de Chrome : dans le panneau Application, la section Back/forward cache propose un bouton qui quitte la page et revient, et indique si la page a été restaurée depuis le bfcache ou la liste exacte des raisons pour lesquelles elle ne l’a pas été. C’est le premier test à faire sur chaque modèle de page important : accueil, catégorie, fiche produit, article, page de recherche.

Lighthouse inclut aussi un contrôle dédié, qui signale les pages ne pouvant pas utiliser le bfcache et les raisons. Pour connaître la situation chez les utilisateurs réels, il existe en revanche l’API notRestoredReasons, disponible dans Chrome, qui expose dans l’entrée de navigation de la Performance API les raisons pour lesquelles une navigation arrière n’a pas été servie depuis le bfcache, y compris celles causées par des iframes tierces :

const nav = performance.getEntriesByType( 'navigation' )[ 0 ];

if ( nav.type === 'back_forward' && nav.notRestoredReasons ) {
	// Exemple : [ { reason: 'unload-listener' }, ... ]
	inviaDiagnostica( nav.notRestoredReasons );
}

Collectées pendant quelques jours dans un système de monitoring, ces données montrent quelles raisons pèsent réellement sur le trafic, et donc par où commencer. Enfin, dans les données du Chrome UX Report, la part des navigations servies depuis le bfcache parmi tous les retours est un indicateur simple pour suivre les progrès dans le temps.

Gérer correctement la restauration

Rendre une page compatible avec le bfcache, c’est aussi accepter qu’elle puisse redevenir visible sans être rechargée. Dans la plupart des cas, c’est exactement ce que l’on veut, mais certains contenus doivent être mis à jour : le compteur du panier après l’ajout d’un produit sur une autre page, l’état de connexion après une identification, les disponibilités et les prix qui changent vite. L’événement pageshow, avec sa propriété persisted, permet de reconnaître une restauration et de ne mettre à jour que ce qui est nécessaire :

window.addEventListener( 'pageshow', ( event ) => {
	if ( event.persisted ) {
		// La page vient du bfcache : mettre à jour les données volatiles
		aggiornaContatoreCarrello();
		inviaVisualizzazione();
	}
} );

Le même événement est le bon endroit pour l’analytics. Une restauration depuis le bfcache est une vue de page à part entière, mais comme les scripts ne sont pas réexécutés, un système qui n’enregistre les visites qu’au chargement ne la voit pas. Les principales plateformes d’analytics gèrent déjà ce cas ; le code sur mesure doit être vérifié.

Pour les pages contenant des données vraiment sensibles, en revanche, l’exclusion est le bon choix. Un espace privé qui affiche des informations personnelles ne doit pas réapparaître avec le bouton Retour après la déconnexion, et pour ces pages Cache-Control: no-store reste l’outil approprié. La règle est simple : exclure en connaissance de cause ce qui est privé, rendre compatible tout le reste.

Le cas de WordPress

Sur les sites WordPress, les pages publiques sont en général compatibles avec le bfcache, mais certaines situations récurrentes les excluent. Des plugins de sécurité ou de cache configurés pour envoyer no-store sur toutes les pages ; des plugins de consentement aux cookies, de statistiques ou de popups qui utilisent encore l’événement unload ; des widgets de chat avec des connexions toujours ouvertes ; des boutiques qui envoient des en-têtes restrictifs sur toutes les pages au lieu du seul panier, du tunnel de commande (checkout) et de l’espace client. Pour les utilisateurs connectés, WordPress envoie des en-têtes interdisant la mise en cache, et il est normal que l’espace d’administration soit exclu.

La vérification est rapide : on inspecte les en-têtes de réponse HTML des pages publiques, on lance le test des DevTools sur les principaux modèles et on identifie le script responsable de chaque raison signalée. Souvent, la correction est un réglage de plugin, une mise à jour ou le remplacement d’un script obsolète.

Bfcache et Speculation Rules : les deux moitiés de la navigation

Dans l’article précédent, nous avons vu comment les Speculation Rules rendent instantanée la navigation vers de nouvelles pages, en les chargeant avant le clic. Le bfcache fait la même chose pour les pages déjà visitées. Ensemble, ils couvrent la plus grande partie de la navigation interne d’un site : l’aller avec le prerender, le retour avec la mémoire du navigateur. Et ils partagent la même discipline : le code ne doit pas supposer qu’une page n’est chargée qu’une fois et vue immédiatement, mais réagir aux événements prerenderingchange et pageshow.

En résumé

Le back/forward cache rend instantané le retour aux pages déjà visitées, en les gardant en mémoire dans leur état complet. Il concerne une part importante des navigations, surtout sur mobile, et ramène à zéro le temps de chargement de ces visites, avec des effets directs sur les Core Web Vitals mesurés sur le terrain et sur l’expérience des personnes qui circulent entre listes et pages de détail.

Le travail consiste surtout à lever des obstacles : no-store là où il n’est pas nécessaire, écouteurs unload, connexions laissées ouvertes. On vérifie avec les DevTools et Lighthouse, on mesure sur les utilisateurs réels avec notRestoredReasons, et l’on gère la restauration avec l’événement pageshow pour mettre à jour les données volatiles et l’analytics. C’est l’une des interventions au meilleur rapport effort/résultat : elle n’allège rien, elle évite simplement de refaire un travail déjà fait.

L’ÉTAPE SUIVANTE

Commençons
par votre site.

Parlez-nous du projet, des problèmes que vous constatez et de vos objectifs. Ensemble, nous définirons une intervention sur mesure.

Demander une analyse

Vous mène au formulaire de la page Contact.

MANAGED SERVER S.R.L.info@corewebvitals.fr +39 02 5656 9681

Du lundi au vendredi · 9 h 30 – 19 h 30 (CET)

Vous préférez un formulaire en ligne ?
Contactez-nous sur managedserver.it ↗