Dans le monde de l’information et de l’ère de la mondialisation tout va très vite ! Qui n’a pas déjà pesté sur un site trop lent ou sur une page blanche qui met trop de temps à se charger ?
En 2010, on disait que le temps de chargement d’une page devait être de 5 secondes. Au-delà, les utilisateurs quittaient le site. En 2020 selon Google, le temps de chargement optimal d’une page serait inférieur à 2 secondes. Le temps de chargement de vos pages est un facteur de référencement.
- Le temps moyen de chargement d’une page est de 3,21 secondes et sur mobile le temps moyen est de 15,3 secondes.
- 25 % des visiteurs s’attendent à ce qu’une page web s’affiche aussi vite sur mobile que sur desktop.
- 38 % des clients abandonnent un site web dont le chargement prend plus de 3 secondes.
- Top 20 des sites américains on un temps de chargement de 1,08 secondes. (meilleur 168 ms)
- Top 10 des site de e-commerce américain on un temps de chargement de 1,96 secondes. (meilleur 177 ms)
Source des chiffres
On comprend sans mal que le temps de chargement de notre application web est primordiale dans le cadre d’un produit « B2C ».
En tant que développeur, que puis-je faire pour améliorer le temps de chargement des pages de mon application ?
L’iceberg qui cache la forêt !

Le sujet est très vaste, on ne pourra pas tout voir, mais on va explorer ensemble un certain nombre de choses.
Le plus important est la perception des utilisateurs. Le problème est que leur perception est totalement subjective. Mais la mesure des performances ne l’est pas.
En mesurant les performances de notre application web, nous allons pouvoir monitorer le temps de chargement (téléchargement des fichiers) et le temps à partir duquel le site est utilisable par l’utilisateur.
Normalement, si vous avez un peu d’expérience web, vous comprenez rapidement qu’on peut agir sur la taille des fichiers ainsi que sur le chargement asynchrone des éléments pour rendre le site utilisable plus rapidement, par exemple.
Mais ça, c’est simplement le sommet visible de l’iceberg !
Comment le navigateur rend une page internet ?
Il y a 4 points à connaître pour comprendre le temps de chargement d’une page.

1 – La latence des requêtes internet
Lorsque dans ma barre de navigation, je rentre l’adresse URL de mon site internet préféré, mon navigateur va contacter des serveurs DNS pour connaître l’adresse du site internet. Une fois que le DNS a répondu, mon navigateur va effectuer une requête au serveur de mon site préféré pour pouvoir télécharger le contenu et l’afficher dans mon dernier onglet ouvert (Le 42e onglet de ma fenêtre, car je ne trouve pas la réponse à ma question existentielle : est-ce que les girafes dorment debout ?). Ce temps dépend de votre connexion internet et de votre localisation par rapport au serveur qui contient les fichiers à télécharger.
Si vous vous connectez à un serveur basé en France ou si vous vous connectez à un serveur au Japon, il n’y a pas de magie, le temps d’aller/retour de l’information qui vient du Japon sera plus lent (entre 1 et 2 secondes d’écart avec une connection rapide). Cet article ne va pas couvrir cette partie, mais si vous avez besoin de rendre accessible votre application sur plusieurs régions du monde, je vous invite à vous renseigner sur les CDN.
Le téléchargement du fichier index.html va déclencher l’ensemble des autres téléchargements nécessaires et introduire le second point.
2 – L’ordre des sources
Le fichier index.html va être téléchargé en premier. Il va être lu et interprété par votre navigateur, et définira ainsi l’ordre de téléchargement des éléments de votre application. Certains éléments seront bloquants pour l’affichage de votre application. Donc le navigateur va attendre ces fichiers avant de passer à la suite. Cela peut ralentir considérablement le temps de chargement de votre page. C’est ici que le chargement asynchrone et l’ordre de chargement doit être effectué afin d’optimiser votre page.
3 – Le chemin critique
Il s’agit du processus que le navigateur utilise pour construire le document Web une fois les fichiers téléchargés depuis le serveur. Dans l’ordre, nous avons l’interprétation des nœuds HTML, du CSS et enfin du Javascript. Chaque langage a son interpréteur.
Les nœuds HTML seront lus de haut en bas. Les images, par exemple, lanceront des requêtes en parallèle du chargement de la page. Le CSS sera également lu sans attendre le téléchargement du fichier. Mais les balises <script> qui ne possèdent pas les attributs async ou defer seront bloquantes. S’il y a trop de balises <script> dans la page, cela peut être un goulot d’étranglement.
Pour accélérer cela, le navigateur effectue un scanner de pré-chargement. Cela permet de lancer le téléchargement des fichiers CSS, Javascript et web fonts en priorité, et même avant que votre navigateur n’en ai besoin.
Mais pour aider ce scanner, vous pouvez ajouter les attributs async et defer afin de s’assurer que ces éléments ne soient pas bloquants.

4 – Construction du DOM
Le navigateur va créer le DOM (Document Object Model) et le CSSOM (CSS Object Model). Une fois créés, le Javascript va pouvoir être interprété et modifier la structure du DOM. Ajouter, déplacer des éléments par exemple.
Dans le cadre d’une Single Page Application (SPA), le temps de l’étape 3 est très court, car le body ne possède qu’une seul DIV avec un id=app. Par contre l’étape 4 sera plus longue, car le Javascript va créer tous les éléments de la page.
Cette étape peut avoir un fort impact sur les performances de votre page.
C’est à l’issue de ces 4 étapes que votre page internet est rendue dans le navigateur de votre utilisateur. Ce sont des éléments mesurables et qui peuvent être suivis.
Les performances perçues
Plus tôt je parlais de performances perçues par l’utilisateur qui sont subjectives. Elles sont subjectives, mais ne peuvent être exclues malheureusement. C’est pour cela qu’il existe des indicateurs de performance qui peuvent aider à suivre les performances « perçues » par vos utilisateurs.
First paint
C’est le temps nécessaire pour exécuter les premiers changements de pixels de la page. Cela peut être imperceptible pour l’utilisateur, par exemple un changement de couleur du fond d’écran d’un blanc à un gris très léger.
First Contentful Paint (FCP)
C’est le temps nécessaire pour afficher le premier contenu à l’utilisateur. Par exemple du texte, une image, un icon. Ce contenu n’est pas forcément utile, simplement visible.
First Meaningful Paint (FMP)
C’est le temps nécessaire pour afficher du contenu utile à l’utilisateur. (une image de girafe par exemple)
Largest Contentful Paint (LCP)
Le temps de rendu de l’élément le plus lourd visible dans la page.
Speed index
Mesure du temps moyen pour que les pixels de votre page soient affichés sur l’écran de votre utilisateur.
Time to interactive
Temps nécessaire pour que l’utilisateur puisse interagir avec la page.
Voici quelques conseils qui permettent d’améliorer la performance perçue par les utilisateurs
Minimiser le chargement initial
Tout ce qui n’est pas visible dans la page de l’utilisateur, notamment les parties qui ne seront visibles qu’après un scroll doivent être chargées de manière asynchrone. Cela augmentera le temps de chargement de la page, mais il sera fait en « background » donc il sera non perceptible. Cela améliorera le temps de rendu de la page qui « semblera » plus rapide à charger.

Le poids des images doit être optimisé. Vous pouvez les avoir en plusieurs dimension, notamment des dimension plus petites pour optimiser le chargement des mobiles. Le CSS permettra de charger la bonne image en fonction de la taille de l’écran.
Les scripts, les images, vidéos, doivent être chargés soit à la fin, soit à la demande. Pourquoi charger le Javascript qui est utile à un utilisateur connecté, alors que votre utilisateur n’est pas encore connecté ?
Éviter les modifications de la page après le premier rendu
Le chargement d’une image en haut de la page qui va pousser le texte vers le bas. Le re-sizing de la page lorsque des éléments arrivent. Ce sont 2 exemples qui donnent une mauvaise perception de votre application.
Si vous avez du contenu long à charger, faites en sorte de leur laisser de l’espace vide qui ne fera pas bouger le contenu de la page lors de leur apparition. Vous pouvez également afficher une zone grisée que vous remplacerez lorsque le contenu sera disponible.
Éviter le délai de chargement des polices d’écriture
Les polices d’écriture peuvent être longues à charger. Vous pouvez définir des polices d’écriture de « secours » (falling back). Faites en sorte de prendre des polices proches de votre police principale afin que la perception du changement ne soit pas trop notable.
Idéalement, vous utilisez une police d’écriture non-exotique qui sera déjà chargée dans le navigateur. Les polices peuvent être partagées par le navigateur entre les sites.
Les éléments interactifs sont interactifs
Merci captain obvious !
Non mais ce que je veux dire par là, c’est que lorsqu’on clique sur un bouton, le temps de rendu n’est pas trop long. Un utilisateur va sentir l’interface « laggy » à partir de 50 ms de réaction. Lorsqu’on parle d’écran 60 Hertz, ça donne un rafraîchissement de l’écran toutes les 16,67 ms. Donc vous avez 3 frames au maximum pour afficher votre rendu avant que votre utilisateur ne commence à se plaindre.

Rendez vos interactions plus rapides
Lorsque vous avez des interactions au clavier par exemple, utilisez l’event keydown au lieu de keyup. Cela peut réduire le temps de réaction et donc de perception de 200 ms. Vous n’avez rien changé à votre code, mais l’utilisateur ressent une rapidité supérieure.
Mesurer la performance
Depuis le début, on parle de performance, de temps de chargement. C’est bien beau, mais comment on fait pour mesurer tout ça Jamy ?
Excellente question Fred !
Il existe plusieurs outils que nous allons voir, vous pouvez utiliser PageSpeed Insights pour mesurer les performances de votre page.

Elle permet de mesurer l’ensemble des points que je vous ai donnés. Ainsi que d’analyser les performances.

Elle donne aussi un certain nombre de conseils pour améliorer la performance.

Et encore d’autres éléments tels qu’un score d’accessibilité, un score de bonne pratique et un score de référencement.
Une fois l’analyse effectuée, vous pouvez utiliser l’onglet « Network » de votre navigateur pour comprendre quels fichiers sont téléchargés ainsi que leur durée et les temps d’exécution.

Lien vers la documentation de l’onglet Network sur firefox
Lien vers la documentation de l’onglet Network sur chrome (avec un tuto en prime)
Il y a également l’onglet « Performance » de votre navigateur qui permet de mesurer les temps d’exécution de votre application. Ainsi que la charge CPU (utilisé pour le parsing entre autres), la mémoire RAM utilisée par votre application.


Lien vers la documentation de l’onglet Performance de firefox
Lien vers la documentation de l’onglet Performance de chrome
Si vous avez des besoins spécifiques de performance, vous pouvez également vous créer votre propre outil de monitoring grâce aux Web API. Vous pouvez également utiliser les Navigation Timing API pour mesurer les performances réseaux en partant de la requête DNS jusqu’au rendu de la page.
Optimisation des images
Alors parlons tout de suite du poids des images, dont vous avez sûrement déjà entendu parler. Ensuite, nous parlerons des autres éléments qui peuvent améliorer le chargement de votre page.

D’après Mozilla, environ 51 % du poids d’un site internet provient des images. En France, nous avons la chance d’avoir des abonnements internet « illimité » et dans le cadre du mobile d’avoir bien souvient plus de « data » que l’on en consomme. Mais dans de nombreux pays, ce n’est pas le cas.
Pour vous donner une idée du coût de visite de votre application web, vous pouvez utiliser ce lien.
Donc pour réduire le coût de bande passante et accélérer le chargement, il existe plusieurs solutions.
Le format le plus optimal
Je vais vous faire un résumé de cette page qui explique très bien quel type d’image il faut utiliser en fonction de votre cas d’usage.
Vous utilisez sûrement des images PNG ou JPEG. Peut-être également des images SVG. Pour optimiser les images SVG, je vous recommande cet outil en ligne. Pour optimiser les images PNG et JPEG, je vous recommande celui-ci ou celui-là. Ces 3 outils vous permettront de diminuer le poids de vos images.
Maintenant, parlons un peu des types d’image en fonction de vos usages.
Type d’image
Le SVG est plutôt conseillé pour des images d’interface comportant peu de couleurs, des icônes et qui ne sont pas photoréalistes. Ils ont aussi l’avantage de pouvoir être affichés dans différentes tailles sans perte de qualité.
Le PNG existe en plusieurs formats :
- couleur en 24 bits + transparence 8 bits
- couleur en 8 bits + transparence 8 bits
- couleur en 8 bits + transparence 1 bits
Je vous recommande de tester les 3 formats et de vérifier que la qualité attendue est conforme. Probablement que le choix de 8/8 bits sera le bon compromis, permettant de diminuer le poids de vos images.
Le format JPEG existe en plusieurs formats. Si vous utilisez ce format, essayez de choisir le Progressive JPEG qui permet d’afficher l’image de manière progressive contrairement au JPEG « normal » qui affiche l’image en qualité maximale, mais de haut en bas. Pour le choix de la « qualité », vous devriez essayer avec 75 % et plus seulement si nécessaire. Le JPEG est le seul type d’image qui ne supporte pas la transparence.
Il existe également le format WebP qui offre de meilleurs taux de compression d’image, permettant encore de réduire le poids. Son adoption côté navigateur est bonne, à l’exception de Safari 14 sur macOS.
Le format AVIF offre d’encore meilleurs taux de compression que le format WebP. Mais il est moins pris en charge par les navigateurs.
Multipliez le nombre d’image pour la même image
Vous pouvez avoir une image dans plusieurs formats d’image afin d’optimiser le temps de chargement de votre site. Oui oui, ce n’est pas une blague !

Vous pouvez utiliser la balise <picture> pour définir plusieurs source d’image. Le navigateur choisira la bonne en fonction des compatibilités et des dimensions. Idéale pour optimiser la navigation sur mobile.
<picture>
<source srcset="/media/cc0-images/surfer-240-200.jpg" media="(orientation: portrait)"/>
<img src="/media/cc0-images/painted-hand-298-332.jpg" alt="" />
</picture>
Pensez que pour les écrans mobile avec des DPI élevées, vous voudrez des images haute résolution. Pour que le navigateur sache quelle image prendre, vous pouvez spécifier une media-query dans l’attribut media de vos balises <source>.
Mozilla recommande de ne pas augmenter la résolution DPI au-delà de « 2x ».
Contrôle de la priorité de téléchargement des images
Il y a 2 choses à savoir, les images contenues dans vos balises <img> et <picture> seront téléchargées en priorité par rapport aux background-image en CSS.
Enfin, vous pouvez définir une priorité de téléchargement avec l’attribut fetchPriority (high / low) sur vos <img> ou <picture>.
Pour vous aider à prioriser le chargement des images, vous pouvez utiliser lazysizes.
Chargez en priorité haute les images au dessus de la ligne de flottaison ou par exemple la première image d’un carrousel.
Pour éviter les problème de décalage et de re-sizing de vos pages, il est conseillé d’utiliser les attributs width et height sur vos images. Cela permet au navigateur de réserver une zone pour votre image. Si l’image ne correspond pas exactement aux dimensions, le re-sizing sera limité mais l’image ne sera pas déformée.
Optimisation du Javascript
Je vais enfoncer une porte fermée par la plupart des développeurs junior et tous ceux qui n’aiment pas le front-end… Vous n’êtes pas obligés d’utiliser un framework Javascript.
Pour les projets simples, du javascript vanille suffira. Et permettra d’alléger le poids de notre page.
Pour les projets plus complets, ok, ça devient intéressant d’utiliser un framework. Pensez à nettoyer le code mort ! Une feature qui n’est plus utilisée sera embarquée pour rien. Sur les vieux projets, ça peut faire pas mal de code.
Vous pouvez creuser le sujet avec les modules javascript.
Pour les bundler, il y a l’incontournable Webpack, mais il y a également le très intéressant Vite ! Si vous êtes sur un projet récent, il est possible que votre bundler soit capable de ne pas embarquer votre code mort, mais seulement si vous avez correctement découpé et importé votre code.
Pensez à activer la minification pour vos environnements de production. Vous devriez également vous renseigner sur les algorithmes de compression que vous pouvez utiliser. Apache, Nginx et les autres sont capables d’envoyer vos fichiers compressés en Gzip mais également en Brotli. À vous de voir quel format est le meilleur dans votre cas.
Ok, donc ça c’était pour le classique !

Retournons dans votre index.html. Dans vos balises <head> vous pouvez indiquer à votre navigateur de « pré-charger » vos scripts à l’aide de l’attribut rel='preload'.
<head>
...
<!-- Preload a JavaScript file -->
<link rel="preload" href="important-js.js" as="script" />
<!-- Preload a JavaScript module -->
<link rel="modulepreload" href="important-module.js" />
...
</head>
Pour le javascript qui n’est pas prioritaire, vous pouvez spécifier l’attribut async. Il sera téléchargé après le contenu prioritaire.
<head>
...
<script async src="main.js"></script>
...
</head>
Vous pouvez aussi charger des parties de script de manière dynamique.
import("./modules/myModule.js").then((module) => {
// Do something with the module
});
Pour ajouter des animations à votre page, évitez d’utiliser des librairies Javascript. Préférez utiliser des librairies CSS si vous n’êtes pas capable de le faire à la main. Mais n’ajoutez pas des kilos de javascript pour 2 ou 3 animations alors qu’il suffirait de 5 à 10 lignes de CSS…
Limitez les écouteurs d’événement (event listener) ou pensez à les attacher au bon élément. Vous pouvez mutualiser des événements grâce au bubbling. Pensez à supprimer les événements qui ne sont plus utiles. Cela va réduire la mémoire utilisée et améliorer les performances d’exécution de votre page.
Optimisation CSS
Les conseils précédents du Javascript sur le code mort et sur la minification reste valide.
Mais dans le fichier index.html on peut aider à prioriser et/ou conditionner le chargement de certains fichiers CSS en ajoutant l’attribut « media » sur vos balises <link>.
<!-- Loading and parsing styles.css is render-blocking -->
<link rel="stylesheet" href="styles.css" />
<!-- Loading and parsing print.css is not render-blocking -->
<link rel="stylesheet" href="print.css" media="print" />
<!-- Loading and parsing mobile.css is not render-blocking on large screens -->
<link
rel="stylesheet"
href="mobile.css"
media="screen and (max-width: 480px)" />
Comme dit plutôt dans cet article, les polices d’écriture (font-family) peuvent augmenter les temps de chargement de vos pages. Car certaines fonts sont très lourdes (plusieurs Mégaoctets). Si malgré cela, vous voulez vraiment utiliser des fonts « exotiques », vous pouvez essayer d’améliorer leur chargement.
Placez l’appel de votre font en haut de votre fichier CSS n’est pas ce qui déclenche le téléchargement de la font, mais c’est sa première utilisation.
/* Font not loaded here */
@font-face {
font-family: "Open Sans";
src: url("OpenSans-Regular-webfont.woff2") format("woff2");
}
h1,
h2,
h3 {
/* It is actually loaded here */
font-family: "Open Sans";
}
Pour accélérer le téléchargement, on peut, comme les fichiers javascript, pré-charger les fonts en les appelants dans le HTML avec l’attribut rel='preload'.
<link
rel="preload"
href="OpenSans-Regular-webfont.woff2"
as="font"
type="font/woff2"
crossorigin />
Vous pouvez même aller jusqu’à utiliser la valeur preconnect si besoin.
Optimisez en fonction de vos besoins
J’ai essayé de vous présenter un large panel de ce qu’il est possible de faire. Dans la plupart des cas, vous n’avez pas besoin de tout mettre en place. Mais savoir que ça existe, c’est le début de futures solutions à vos problèmes.
Malgré tout, il y a des trucs simples à faire. L’optimisation des images et du CSS me semble plutôt simple à faire. Découpez vos fichiers CSS par media-query ce qui permet leur chargement en fonction du device utilisé.
Mon dernier conseil : faites un tuto sur les animations CSS. Les animations simples ne sont vraiment pas compliquées lorsqu’on a compris ! Ouvrir/fermer une div, c’est 3 lignes de CSS !
