jan. 2016

Les performances du chemin critique du rendu

Optimiser les performances du chargement d’un site web est crucial autant d’un point de vue ergonomique afin améliorer l’expérience des utilisateurs que d’un point de vue commercial pour convertir ces derniers. Pour autant, la notion de “chargement” ou de “vitesse de chargement” reste assez vague et ne nous apporte pas forcément des critères pertinents pour évaluer ce qui est optimisé. Avec cet article je vais essayer de comprendre quels sont les critères essentiels à prendre en compte pour évaluer les performances d’un site web, et quelles sont les moyens pour le développeur front end de les améliorer.

  • Comprendre le critical rendering path
  • Premier objectif : limiter les ressources critiques
  • Deuxième objectif : minimiser la taille des ressources
  • Troisième objectif : optimiser les requêtes
  • Mesurer pour évaluer
  • TL;DR
  • Ressources sur l’optimisation des performances

Comprendre le critical rendering path

Pour cet article je vais partir d’un postulat : celui qu’une meilleure expérience utilisateur dépend de la vitesse d’un site web à s’afficher. Ou du moins l‘“illusion” que celui-ci est chargé puisque l’important reste d’afficher en priorité ce que l’utilisateur perçoit directement. Peu importe pour le moment que ce qui n’est pas visible ne soit pas encore entièrement chargé.

mental context switch

Figure 1 : au bout d’une seconde, la moyenne des utilisateurs exprime un “mental context switch”, c’est-à-dire qu’ils commencent à perdre l’intérêt qu’ils ont d’obtenir ce qu’ils sont venus chercher sur le site. Au-delà des 10 secondes, les utilisateurs quittent le site. (source : lean websites)

Pour répondre à ce postulat, il faut alors revenir à une notion de base du fonctionnement de tout site web : le chemin critique du rendu. Ce “critical rendering path” (CRP) est une séquence de différentes étapes que parcourt le navigateur pour convertir les fichiers d’un site web (HTML, CSS, etc.) envoyés au serveur en pixels s’affichant concrètement sur l’écran. Ce chemin est une notion clef des performances web puisque le comprendre et l’optimiser permettra justement d’améliorer, si ce n’est le temps de chargement total de la page, au moins la perception qu’aura l’utilisateur de ce temps de chargement.

En résumé, le chemin critique du rendu suit les étapes suivantes :

  • l’utilisateur entre une url dans le navigateur qui envoie alors une requête afin d’accéder au fichier HTML correspond à la page ;
  • le navigateur analyse le fichier HTML reçu et commence à construire le DOM ;
  • dans la grande majorité des cas, il envoie des requêtes au serveur pour obtenir les fichiers qui lui manquent, notamment les fichiers CSS et JS ;
  • le navigateur analyse le CSS et construit le CSSOM ;
  • le navigateur analyse le JS et l’interprète, modifiant alors éventuellement le DOM et le CSSOM ;
  • il construit le “render tree” (arborescence d’affichage) sur la base du DOM et du CSSOM ;
  • il met en route la phase de “layout” qui calculera les différentes dimensions et distances du rendu de la page ;
  • puis enfin le navigateur affichera (“paint”) les différents pixels de la page.

Comprendre le chemin critique du rendu nous permet déjà d’identifier les contraintes et éléments qui peuvent bloquer le rendu de la page, notamment :

  • la page web n’est par exemple affichée que lorsque l’arborescence d’affichage (render tree) est construite, et donc par extension uniquement lorsque le DOM et le CSSOM sont construits. Le CSS est donc un élément bloquant : le navigateur suspend l’affichage du contenu tant qu’il n’a pas analysé et interprété le CSS.
  • Le JS n’est exécuté que lorsque le CSSOM est construit car le navigateur ne sait pas encore si le script va manipuler le DOM qui se construit et/ou le CSSOM. Lorsqu’il rencontre un script, le navigateur suspend la construction du DOM et cède le contrôle à l’exécution Javascript. Le javascript est donc lui aussi bloquant.

le render tree

Figure 2 : le render tree se compose du DOM et du CSSOM (source)

Sur ces différentes questions, Ilya Grigorik, ingénieur spécialisé dans les performances web à Google, propose un cours en ligne (voir les liens en fin de section) qui explique clairement les différents processus du chemin critique du rendu. Ce cours prend l’exemple d’une page HTML simple et en illustre le CRP ainsi :

exemple de crp

Figure 3 : CRP d’une page HTML simple. Cet exemple simplifie le processus en partant du principe que le navigateur ne fournit pas de CSS par défaut, ce qui n’est jamais le cas.

Ici le critical rendering path est assez simple : le navigateur fait la requête de la page HTML et ne fait rien tant qu’il ne l’a pas reçu (on voit ici qu’il reste idle). Une fois le fichier reçu, il construit le DOM et affiche directement la page, puisque celle-ci ne contient ni CSS (donc pas de phase de construction du CSSOM ni de phase de layout dans cet exemple) ni JS (donc pas de phase d’exécution du script et d’éventuelles nouvelles manipulation du DOM et du CSSOM).

Un autre exemple est ensuite donné, celui d’une page ayant justement des fichiers CSS et JS externes :

exemple de crp avec des fichiers

Figure 4 : CRP d’une page HTML faisant appel à des fichiers CSS et JS externes

Dans ce second exemple, l’initialisation du CRP reste le même : le navigateur requête le HTML et attend. À la réception et à l’analyse du HTML, il requête alors le CSS et le JS, deux actions qu’il peut faire en parallèle. L’attente de la réponse du fichier CSS bloque le rendu de la page, puisque celle-ci nécessite la construction du CSSOM. Le fichier JS quant à lui ne peut pas être analysé par le navigateur tant que le CSSOM n’est pas construit. À la réception des fichiers, le navigateur construit donc le CSSOM, puis exécute le javascript, finit de construire le DOM éventuellement manipulé par le javascript, et affiche enfin la page.

Ces détails sur le chemin critique du rendu nous permettent de comprendre les trois critères essentiels à prendre en compte pour les performances de chargement d’un site web, et donc les trois objectifs que nous devrions suivre pour les optimiser :

  • puisque le rendu de la page est bloqué par la prise en compte de ressources CSS et JS, il s’agira de limiter le nombre de ressources “critiques”, c’est-à-dire nécessaires dans le CRP et susceptibles de bloquer le rendu. Il sera par ailleurs nécessaires d’indiquer au navigateur que les ressources “non critiques” peuvent être prises en charge plus tard. Le critère à identifier ici est donc le nombre de ressources critiques ;
  • puisque le navigateur est dans l’attente des ressources externes, il s’agira de limiter la taille des fichiers requêtés et analysés afin qu’ils soient récupérés et interprétés plus rapidement. Le critère à identifier est donc la taille des ressources critiques (pour améliorer la vitesse de chargement du contenu critique) aussi bien que des ressources non-critiques (pour améliorer la vitesse globale du chargement de la page) ;
  • puisque certaines étapes sont dépendantes les unes et autres et allongent le chemin critique du rendu (par exemple des fichiers CSS dépendant les uns des autres retardent la construction du CSSOM), il s’agira de limiter le nombre de requêtes différentes envoyées au serveur en optimisant notamment les dépendances entre ressources, c’est-à-dire en requêtant ensembles les ressources dépendantes les unes des autres. Le critère à identifier ici est donc la longueur du chemin critique et plus généralement du rendering process.

Ainsi, si l’on applique ces trois critères à la figure 3 par exemple, on calcule qu’il y une ressource critique (le HTML), que celle-ci fait 5 kB et qu’il ne faut qu’une boucle réseau pour rendre la page (requête et réponse du HTML). La figure 4 est légèrement moins performante en revanche : 3 ressources critiques (le HTML, le CSS, le JS), 11 kB de ressources critiques et 2 boucles réseaux (requête et réponse du HTML, requête et réponse du CSS et du JS faits en parallèle). On imagine dès lors la complexité d’un CRP nécessitant plusieurs ressources CSS, JS, fontes, etc.

Premier objectif : Limiter les ressources critiques

comparaison de crp

Figure 5 : différence d’affichage entre un site dont le chemin critique du rendu est optimisé et un site où il ne l’est pas (source)

Les outils de critical CSS pour distinguer le style critique

Afin d’afficher la page, le navigateur a besoin de construire le “render tree” sur la base du DOM et du CSSOM. Il attend ainsi d’avoir le CSS nécessaire à la page avant d’afficher celle-ci. Pour autant, le navigateur n’a pas forcément besoin de connaître tout le CSS de mon application ou de mon site web pour afficher la première page. Même plus précisément, il n’a besoin de connaître que le style de la portion de page que verra l’utilisateur au chargement, c’est-à-dire la section au-dessus de la ligne de flottaison (si l’on met de côté le débat sur l’existence de cette dernière). L’idée est donc de proposer deux CSS différents, au minimum :

  • le CSS nécessaire à l’affichage de la première portion de page directement visible au chargement, qui sera intégré directement dans le HTML afin de limiter les requêtes, comme nous avons pu le voir ;
  • le reste du CSS dont le chargement sera différé pour ne pas bloquer l’affichage de la page. Filament group propose à ce titre un script pour différer le chargement d’un fichier CSS.

La difficulté tient alors dans le fait de déterminer ce qui relève du CSS critique ou non. Certains le font directement à la main, ce qui peut s’avérer rapidement complexe. Pour les autres, des outils assez efficaces existent, et sont notamment listés par Ben Edwards sur CSS tricks. Pour ma part j’utilise la contrib Grunt criticalcss qui génère le CSS critique à partir d’un fichier donné et de quelques informations (taille de fenêtre ciblée, buffer, etc.).

L’attribut async pour signaler les scripts non critiques

Si tous les scripts JavaScript sont bloquants pour l’analyseur, c’est parce que le navigateur ne sait pas si le script agira sur le DOM et le CSSOM tant qu’il ne l’a pas parcouru. Dans le doute il bloque donc le rendu pour analyser et interpréter le CSS. Une bonne pratique dans ce cas est d’aider le navigateur en indiquant qu’un script donné n’est pas critique et qu’il ne doit pas forcément être exécuté de manière synchrone. En ajoutant l’attribut async à la balise du script, le navigateur fait la requête du fichier au serveur, mais il continue de construire le DOM. Le script sera exécuté lorsqu’il sera reçu, mais son exécution n’a pas bloqué la construction du DOM et le rendu.

exemple de fichier async

Faire du chargement à la demande des images

L’idée est toute simple et symbolise cette optimisation du Critical Rendering Path : pourquoi faire bloquer l’affichage avec des requêtes pour des contenus qui ne sont pas directement visibles pour l’utilisateur ? Pourquoi ne pas faire ces requêtes au moment même où l’utilisateur en a réellement besoin ? C’est une optimisation radicale et essentielle, notamment en ce qui concerne l’affichage des images : nous n’allons pas charger les images qui ne sont pas encore visibles.

La technique est donc d’afficher “en dur” les images du CRP afin qu’elles soient affichées rapidement, et pour les images qui ne sont pas directement visibles, nous allons retarder leur affichage. Plusieurs plugins nous simplifient la tâche pour faire cette technique de “lazy loading” que nous recherchons : https://github.com/tuupola/jquery_lazyload est un des scripts les plus utilisés, ou encore https://github.com/vvo/lazyload, utilisé par des grands groupes comme lequipe.fr, le monde.fr ou voyages-sncf.com.

Second objectif : Minimiser la taille des ressources

Optimiser les images

En moyenne aujourd’hui, une page web fait 1,5 mB et les principaux responsables de ce poids sont les images (60% du poids d’un site en moyenne). La priorité reste donc d’optimiser les images afin de réduire leur poids au maximum sans pour autant trop altérer leur qualité. Pour cela les task runners comme Gulp ou Grunt sont très pratiques, et proposent notamment gulp-imagemin et grunt-contrib-imagemin.

Au-delà du simple fait de compresser et d’optimiser les images, il est également intéressant de s’interroger sur les formats les plus optimaux en fonction de l’image elle-même, voire parfois de remplacer une image par des formes vectorielles (svg), des web fontes ou encore des effets CSS. Google developper propose ainsi une revue des questions à se poser pour optimiser des images.

“Minifier” le CSS et le javascript

Les espaces et l’aération des fichiers sont utilisés pour la lisibilité et la maintenabilité des fichiers pour les développeurs, pas pour les machines. Le navigateur ne s’intéressant pas aux espaces, il est judicieux de les retirer des fichiers de production afin de minimiser leur poids. Plusieurs tâches Grunt et Gulp permettent ainsi de supprimer ces espaces inutiles, autant pour les fichiers CSS et JS que pour le HTML. J’utilise pour ma part grunt-contrib-uglify pour le JS et grunt-csso pour le CSS.

Activer la compression gzip

gzip est un algorithme de compression très puissant utilisé par la plupart des serveurs et supporté par tous les navigateurs modernes. Le seul soucis est qu’il n’est généralement pas activé par défaut. La solution est très simple et très bénéfique pour optimiser nos applications et site web : pour les serveurs Apache, il suffit seulement de l’activer depuis un fichier .htaccess.

example de script de compression

Prévenir la complexité des ressources

Le poids d’un fichier, s’il est primordial, n’est pas le seul enjeu à prendre en compte pour optimiser le traitement des ressources. La complexité de ces ressources a également sa propre influence : plus une ressource est complexe, plus le navigateur nécessitera du temps pour l’interpréter.

Au niveau de la structure de nos pages, une première bonne pratique à avoir est de s’appliquer à écrire du HTML aussi sémantique et valide que possible. Plus il y a d’erreurs dans le HTML, plus le navigateur devra fournir du travail (et donc du temps) pour rectifier ces erreurs pour construire le DOM.

Au niveau du style de nos pages, un autre exemple simple est donné par la notion de profondeur d’un sélecteur CSS. Plus le sélecteur CSS sera complexe et dépendant de plusieurs niveaux de noeud (fils de… fils de… etc.), plus le navigateur devra calculer et prendre en compte les contraintes pour trouver le ou les éléments sélectionnés.

exempel d'amélioration du css

Figure 6 : une classe seule (à gauche) permet d’identifier plus rapidement des éléments et demande moins de calcul au navigateur qu’un sélecteur complexe présentant plusieurs niveaux de profondeur et des expressions spécifiques.

La manière dont le navigateur interprète le CSS n’est pas intuitive. Il le parcourt en effet de la droite vers la gauche. Aussi, sur le deuxième exemple de la figure 6, le navigateur va parcourir la page pour trouver toutes les balises input, puis va parcourir les parents de ces inputs afin d’essayer de trouver un .form-group, et ainsi de suite. L’idéal est ainsi d’utiliser des sélecteurs les plus spécifiques possibles, et de minimiser au possible les imbrications inutiles dans le CSS, souvent malheureusement favorisées par les “nested selectors” des prép-processeurs. Il est ainsi recommandé de se limiter à 3 niveaux de sélecteurs (c’est ce que recommande les designers d’AirBNB par exemple), voire à 4 (ce que recommande l’ “inception rule”) ce qui, dans une perspective d’approche modulaire du code, ne devrait pas être trop difficle.

Un outil comme grunt-css-count fournit par ailleurs des indicateurs intéressants sur le CSS et permet d’avoir un audit automatisé de l’utilisation des différents types de sélecteurs.

rendu du css count

Figure 7 : csscount renvoie des informations comme le nombre de sélecteurs utilisés, le poids d’un fichier ou encore la répartition des sélecteurs selon leur niveau de profondeur dans le CSS (de D1 à D11). À noter que connaître le nombre de sélecteurs est essentiel dans certains projets web puisque IE9 est limité à 4095 sélecteurs

De manière générale enfin, c’est sans doute la complexité globale de l’application ou du site web qu’il est généralement pertinent d’interroger. Certains éléments ne sont pas forcément nécessaires ni pour véhiculer un message ni pour l’expérience générale sur le projet. Comme le rappelle Ilya Grigorik, la ressource la plus rapide et la plus optimisée reste celle qui n’est pas envoyée. Par exemple, il peut être pertinent de questionner l’intérêt d’un carousel : les utilisateurs le consultent-ils, même partiellement ou en totalité ? Son intérêt est-il pertinent au regard de ce qu’il “coûte” en terme de performance ? Le design d’un site web et ses performances sont ainsi liés : si une bonne expérience utilisateur commence par un site fluide et rapide, un design soigné et pertinent permet à l’inverse d’éliminer dès la conception des obstacles non négligeables à la rapidité et à la réactivité du site.

Troisième objectif : Optimiser les requêtes

Concaténer les ressources

Le meilleur moyen d’optimiser les requêtes reste tout d’abord d’en réduire au maximum le nombre. Les connexions HTTP pouvant prendre un temps conséquent, notamment sur mobile ou le temps de latence est souvent plus long, en limiter le nombre permettra d’optimiser grandement le temps de chargement de la page. Le nombre de requêtes peut être ainsi limité en concaténant, c’est-à-dire en joignant dans un même fichier, différentes ressources :

  • la concaténation en CSS peut ainsi se faire via la méthode @import utilisée avec des préprocesseurs comme SASS ou LESS afin de n’avoir en production qu’un unique fichier CSS (et c’est d’ailleurs pourquoi il serait contre-performant d’utiliser la méthode @import directement en CSS) ;
  • la concaténation en JS peut se faire à l’aide de require.js ou des tasks runners comme Grunt ou Gulp. J’utilise pour ma part grunt-contrib-concat. Cela permet de joindre ensemble le fichier JS ainsi que toutes ses dépendances, réduisant donc également la longueur du chemin critique ;
  • la concaténation peut se faire également sur les images en les joignant dans une fonte quand cela est pertinent par exemple, ou en les concaténant dans un sprite, par exemple avec csssprites.

Activer la mise en cache

La plupart des recommandations de performances concerne la première connexion des visiteurs sur un site ou une application. La mise en cache permet ensuite d’optimiser ces ressources pour les utilisateurs qui reviennent sur le site. En effet, un utilisateur qui revient sur le site ne devrait pas à avoir à recharger à nouveaux toutes les ressources, quand bien même celles-ci sont optimisées. C’est justement ce à quoi répond le cache HTTP en proposant de conserver ces ressources pour un temps donné dans le navigateur.

Sur les serveurs Apache, la mise en cache peut s’activer et se gérer depuis le fichier .htaccess :

fichier htaccess

Notons également que la mise en cache peut-être bénéfique sans pour autant être activée. Par exemple avec le “cross-site caching”, c’est-à-dire lorsque l’on utilise des ressources populaires, sûrement utilisées sur d’autres sites, et donc probablement déjà dans le cache du navigateur de l’utilisateur. C’est par exemple le cas lorsque l’on utilise des fontes populaires chargées depuis Google Fonts (et non en local) ou encore lorsque l’on utilise des CDN pour les librairies javascript les plus utilisées. Il est ainsi probable que la plupart des utilisateurs aient déjà la fonte Open Sans et la librairie jQuery dans le cache de leur navigateur.

Préparer les requêtes pour le navigateur

Les navigateurs modernes sont optimisés pour tenter de prédire et d’anticiper l’activité des utilisateurs sur un site web. Or, plusieurs outils existent afin de justement aider le navigateur dans ces prédictions, et de lui indiquer et préparer les requêtes à venir afin d’accélérer leur prise en compte. Après tout, nous connaissons mieux le comportement plausible des utilisateurs ainsi que les ressources qui pourraient être nécessaires à court terme.

Parmi ces outils, on trouve ainsi :

  • la pré-résolution de requêtes DNS : si l’on charge plus loin dans la page des ressources (CSS, JS, images, …) issues d’un domaine particulier, il est possible d’indiquer au navigateur, dans le <head> de la page, qu’il y aura besoin de résoudre un nom de domaine en adresse IP. Le navigateur pourra donc faire cette requête plus tôt. L’astuce fonctionne aussi très bien lorsqu’un lien d’une page renvoie à un autre domaine, sur un site compagnon ou un blog par exemple.

example de prefetching

  • indiquer les ressources critiques : en plus des recommandations données plus haut sur le fait de limiter les ressources critiques et de différer le chargement des autres ressources, il est possible d’indiquer au navigateur les ressources critiques nécessaires rapidement au chargement de la page. Les ressources marquées par l’attribut “subresource” seront ainsi chargées le plus tôt possible par le navigateur.

exemple de subresource

  • pré-charger les ressources futures : il est possible d’utiliser les moments où le navigateur ne fait rien pour lui demander de pré-charger des ressources qui pourraient être utilisées dans une navigation future. Ainsi, à l’inverse de l’attribut précédent qui indique au navigateur les ressources à charger en priorité, l’attribut “prefetch” indique au navigateur les ressources qui ont le moins d’importance, en l’occurrence ici celles qui ne sont pas même sur la page actuelle. Cela permet d’indiquer au navigateur les ressources qui pourraient être utilisées et de les placer d’ores-et-déjà dans le cache, et par là optimiser le temps de chargement des pages à venir.

exemple de prefetching

  • pré-afficher une page entière : l’attribut “prerender” va même au-delà du “prefetch” puisqu’il permet de mettre en oeuvre prématurément les requêtes et les téléchargements nécessaires à l’affichage complet d’une page, sans pour autant afficher la page en question. Le pré-affichage est ainsi similaire au fait d’ouvrir une page dans un nouvel onglet pour lui laisser le temps de se charger avant de la consulter, à ceci près que tout se passe ici en arrière-plan.

exemple de prerendering

Limiter les modifications du DOM

Cette dernière recommandation concerne peut-être moins la question de l’optimisation des requêtes mais reste néanmoins pertinente pour l’amélioration globale du chargement de la page et pour la réduction du chemin critique du rendu. Comme nous avons pu le voir, la construction du DOM est assez lente. Solliciter des nouvelles constructions peut demander inutilement beaucoup de temps, surtout qu’une modification sur le DOM obligera le navigateur à recalculer le style des éléments et donc sa mise en page. Il en va de même pour la manipulation du CSSOM. On y réfléchira ainsi à deux fois à la réelle utilité de modifier les éléments d’une page à l’aide de jQuery par exemple.

Par ailleurs, la question des performances devient un critère crucial pesant en faveur d’un framework qui limite les modifications directes ou complètes du DOM, à l’image de React par exemple qui utilise l’intermédiaire d’un DOM virtuel optimisé pour les modifications.

Mesurer pour évaluer

Les recommandations ci-dessus ne représentent qu’une partie de ce qu’il est possible de faire pour améliorer les performances de son site ou de son application. On trouvera dans les ressources plus bas des articles proposant d’autres méthodes pour approfondir cette démarche. Un dernier point à aborder succinctement reste néanmoins crucial : afin d’évaluer pertinemment les performances d’une application, il faut pouvoir mesurer ces performances. Voici donc une liste d’outils pertinents pour ces mesures :

  • Les “outils de développement” des navigateurs : l’outil le plus directement accessible reste l’outil de développement qui se trouve dans tous les navigateurs. Il permet d’avoir facilement et rapidement des indicateurs essentiels pour mesurer les performances.

chrome devtool network

Figure 8 : Aperçu de l’outil “network” de Google Chrome au chargement de la page d’accueil du monde.fr. On y voit le “resource waterfall” qui liste toutes les requêtes envoyées par la page afin qu’elle s’affiche. En bas à gauche nous pouvons retrouver des critères qui nous intéressent particulièrement dans l’optique d’une optimisation : le nombre de requêtes nécessaires à l’affichage (440 ici), le poids total de la page (1,5 mB) et le temps de chargement complet (21 secondes).

chrome devtool network

Figure 9 : Analyser les temps de chargement et de rendu de chaque fichier nous permet ainsi d’identifier les sources à optimiser. Dans cet exemple donné par Barbara Bermes on constate que plusieurs gros fichiers CSS sont chargés, que les images mettent du temps à être récupérées et encore plus de temps à s’afficher ou encore que plusieurs requêtes javascript sont envoyées.

chrome devtool timeline

Figure 10 : Aperçu de l’outil “timeline” de Google Chrome au chargement de la page d’accueil du monde.fr. La timeline permet par ailleurs d’identifier la répartition du temps en fonction des différentes actions du navigateur, et permet donc d’identifier les éventuelles actions prenant trop de temps.

chrome devtool audits

Figure 11 : Aperçu de l’outil “audits” de Google Chrome au chargement de la page d’accueil du monde.fr. Cet onglet analyse la page lors de son chargement et propose des suggestions sur l’optimisation de ses performances.

  • PageSpeed Insights est un outil essentiel de Google permettant de mesurer les performances d’un site sur mobile et desktop selon des critères de vitesse et d’expérience utilisateur. L’outil évalue les performances du site donné et propose des recommandations ;

overview pagespeed

overview pagespeed

Figure 12 : Analyse PageSpeed du site lemonde.fr. On y voit le score pageSpeed ainsi que les recommandations à suivre afin d’améliorer ce dernier.

  • dans la lignée de PageSpeed Insights, Mozilla propose yslow. On pourra surtout utiliser le très bon WebPageTest;

webpagetest

Figure 13 : Aperçu de WepPageTest au chargement de la page d’accueil du monde.fr. On voit ainsi que l’outil est beaucoup plus précis, et propose des critères plus détaillés comme le “first byte” (temps entre le début de la connexion et la réception du premier byte par le navigateur, après les éventuelles redirections ou les éventuelles latences) ou encore le “start render” (temps avant que le contenu commence à apparaître). Un critère très utilisé est aussi celui du speed Index, le temps moyen (en ms) auquel les parties visibles (donc critiques) d’une page sont affichées. Paul Irish recommande qu’il soit inférieur à 1000.

webpagetest

webpagetest

Figure 14 : WepPagetest permet également de faire des comparaisons entre plusieurs sites, ici par exemple entre lemonde.fr et lequipe.fr. Les résultats affiches des aperçus du chargements ou encore plusieurs graphs illustrant les différences de performances entre les sites comparés (speed index, tailles des ressources, requêtes, …). Pertinent pour comparer son site à celui de ses concurrents, ou encore pour comparer un site optimisé en preprod avec son ancienne version non-optimisée.

  • en complément de la timeline des outils de développement ou de WepPageTest, je souligne au passage un tout nouvel outil encore expérimental proposé par Paul Lewis, spécialiste des performances web à Google. Il s’agit de “Big Rid” qui permet d’analyser des “traces” spécifiques, une trace étant une partie ou la totalité de la timeline (généralement exportée en JSON). L’outil s’utilise avec une interface visuelle ou en ligne de commande, et peut-être très utile pour mesurer une fonctionnalité particulière notamment.

illustration de l'outil big rid

Figure 15 : Aperçu d’un graphe issue d’une trace, généré par Big Rid (source)

  • toujours dans les outils de Google, Analytics offre des indicateurs intéressants pour évaluer les performances d’un site, notamment sa vitesse, le temps de chargement des pages, ou encore le “temps utilisateur”. La rubrique “suggestions relatives à la vitesse du site” ne fait en revanche que renvoyer à PageSpeed Insights, mais permet cependant d’avoir une vue d’ensemble sur les suggestions à suivre pour chaque page du site ;
  • l’API Navigation Timing permet d’obtenir différents critères pour évaluer les performances d’un site à toutes ses étapes de chargement et de construction. Elle s’utilise à l’aide d’un script amorcé au chargement de la page;
  • Notons enfin qu’il est possible d’installer sur son serveur une instance de HTTP Archive qui permettra d’obtenir des chiffres sur tous les critères mentionnés auparavant, mais également de générer des graphs sur l’évolution dans le temps de ces critères, ou encore de comparer ces chiffres à ceux d’éventuels concurrents. Barbara Bermes explique clairement sur son blog comment mettre en place cet outil. Ilya Grigorik propose également des requêtes SQL à utiliser avec HTTP Archive pour mesurer certains critères des sites existants comme les frameworks, les plus utilisés, les content-type les plus utilisés, etc.

Les performances de chargement d’un site web sont un enjeu crucial pour tout projet web, car elles sont le fondement de dimensions aussi essentielles et différentes que l’expérience utilisateur, l’image de la marque ou, comme nous le verrons dans les prochains articles, le SEO et la “soutenabilité” (éco-conception). À ce titre, ces quelques recommandations pour optimiser le front-end pourront paraître nécessaires mais pas suffisantes. D’une part, la sensibilité du sujet fait que de nouvelles recommandations et de nouveaux outils émergent très régulièrement, rendant cette liste d’ores-et-déjà si ce n’est obsolète au moins non-exhaustif (Google vient par exemple le mois dernier de proposer un nouvel outil pour optimiser le chargement des pages sur mobile). D’autre part, des performances optimisées se pensent en réalité dès la conception et le web design, doivent également être considérés dans le choix des outils et des méthodes pour le back end, et ne peuvent donc se résumer aux seules méthodes applicables en front end.

TL;DR

  • le “critical rendering path” est une séquence de différentes étapes que parcourt le navigateur pour convertir les fichiers d’un site web (HTML, CSS, etc.) envoyés au serveur en pixels s’affichant concrètement sur l’écran. Ils sont critiques car nécessaire à l’affichage de la page. Mais il est possible de réduire le nombre et le poids de ces fichiers critiques pour que la page se charge plus rapidement ;
  • le premier objectif est de limiter les ressources critiques en “inlinant” le CSS critique et en ajoutant un attribut async sur le JavaScript non critique ;
  • le second objectif est de minimiser la taille des ressources en optimisant les images, en “minifiant” le CSS et le JS, en activant la compression gzip et en réduisant la complexité du code ;
  • le troisième objectif est d’optimiser les requêtes en concaténant des ressources, en activant la mise en cache, en préparant les requêtes pour le navigateur (pre-browsing) et en limitant les modifications du DOM ;
  • il reste enfin indispensable de mesurer et d’évaluer les critères pertinents de chargement de la page, grâce à des outils comme les outils de développement des navigateurs, PageSpeed Insights, WebPageTest ou encore HTTP Archive.

Ressources sur l’optimisation des performances :