L'optimisation des sites web est à l'ordre du jour. Si nous voulons améliorer l'expérience utilisateur, en particulier sur les mobiles, nous devons comprendre le fonctionnement des navigateurs. Par Sanjay Purswani.
Par Sanjay Purswani
L'optimisation est affaire de vitesse et de satisfaction.
- Pour l'expérience utilisateur (UX) notre front end doit livrer rapidement une page web performante,
- et pour l'expérience développeur (DX) le front end doit être rapide, facile et exemplaire.
Nous aurons ainsi non seulement des utilisateurs et développeurs heureux, mais également un meilleur SEO, Google ayant un penchant pour les sites optimisés.
Si vous avez déjà passé du temps à améliorer votre score Google Pagespeed Insights, cet article apportera quelques lumières sur le sujet et sur la pléthore de stratégies dont nous disposons pour optimiser le front end.
Contexte
Dans le cadre d'un projet de mise à jour (en React ?) mon équipe s'est replongée dans le code existant, ce qui m'a amené à revoir la construction de notre front end. Je me suis rendu compte assez vite que le navigateur serait un facteur essentiel dans notre approche — et nos connaissances en la matière un obstacle tout aussi grand.
Approche
Nous ne pouvons pas contrôler le navigateur, ni modifier son comportement, mais nous pouvons comprendre comment il fonctionne de façon à optimiser ce que nous lui demandons de charger.
Heureusement, les fondamentaux sont assez stables, bien documentés et ne changeront pas significativement pendant encore un bon bout de temps.
Cela nous donne donc un objectif.
De l'autre côté, le code, l'architecture, les patterns sont sous notre contrôle. Ils sont plus flexibles, ils changent à un rythme plus élevé, et nous offrent plus d'options.
Par conséquent, j'ai décidé de travailler en partant de l'extérieur, c'est à dire en essayant d'imaginer ce que le résultat final devrait être pour ensuite me faire une opinion sur l'écriture du code. Dans cette première partie, nous allons nous concentrer sur tout ce que nous devons savoir sur le navigateur.
Ce que fait le navigateur
Voici un exemple d'HTML assez simple :
<!DOCTYPE html>
<html>
<head>
<title>The "Click the button" page</title>
<meta charset="UTF-8">
<link rel="stylesheet" href="styles.css" />
</head>
<body>
<h1>
Click the button.
</h1>
<button type="button">Click me</button>
<script>
var button = document.querySelector("button");
button.style.fontWeight = "bold";
button.addEventListener("click", function () {
alert("Well done.");
});
</script>
</body>
</html>
Comment le navigateur rend la page
Lorsque le navigateur reçoit notre HTML, il en fait l'analyse syntaxique (parsing), le réduit à un vocabulaire compréhensible par lui, qui est cohérent d'un navigateur à l'autre grâce à la spécification HTML5 DOM. Puis il se lance dans une série d'étapes visant à la construction et au rendu de la page. En voici une vue générale :
- Utiliser notre HTML pour créer le DOM (Document Object Model).
- Utiliser notre CSS pour créer le CSSOM (CSS Object Model).
- Exécuter les scripts sur le DOM et le CSSOM.
- Combiner le DOM et le CSSOM pour former l'arbre de rendu (render tree).
- Utiliser cet arbre de rendu pour disposer les éléments (taille et position).
- Peindre tous les pixels.

Étape 1 — HTML
Le navigateur commence par la lecture du markup, du début jusqu'à la fin, et l'utilise pour créer le DOM en le traduisant en noeuds :

stratégies d'optimisation de chargement HTML
styles en tête, scripts à la fin du document
Même s'il y a des exceptions et des nuances à cette règle, l'idée générale est de charger les styles aussi tôt que possible et les scripts le plus tard possible. La raison en est que les scripts ont besoin d'attendre la fin du parsing du HTML et du CSS avant de pouvoir être exécutés.
minification & compression
Cela s'applique à tous les contenus, HTML, CSS, JavaScript, images et autres ressources.
La minification supprime tous les caractères redondants, dont les espaces, les commentaires, les points-virgules inutiles, etc.
La compression, par exemple GZip, remplace des données répétées à l'intérieur du code ou d'autres ressources par un pointeur vers l'instance originale. On comprime ainsi massivement la taille des téléchargements et on s'appuie sur le client pour la décompression. On peut ainsi réduire de 80 à 90% la taille du chargement — par exemple sur le seul Bootstrap on gagne 87%.
accessibilité
Cela n'améliorera peut-être pas beaucoup la performance de vos pages, mais certainement la satisfaction de vos usagers handicapés ou diminués. Utilisez les labels aria
, n'oubliez pas alt
, le texte alternatif sur les images, et tout ce qui compte pour ne pas laisser des utilisateurs sur le bord du chemin.
Utilisez des outils comme WAVE pour identifier les points d'amélioration possibles en termes d'accessibilité.
Étape 2 — CSS
Lorsque le navigateur trouve un noeud relatif au style, qu'il soit externe, interne, inline, il s'arrête de rendre le DOM et il utilise ces noeuds pour créer le CSSOM. C'est pourquoi l'on dit que CSS "bloque le rendu". Vous trouverez ici les pour et les contre des différents types de style.
// Feuille de styles externe
<link rel="stylesheet" href="styles.css">
// Styles internes
<style>
h1 {
font-size: 18px;
}
</style>
// Styles inline
<button style="background-color: blue;">Click me</button>
Les noeuds du CSSOM sont créés comme ceux du DOM, ils seront ensuite combinés mais voici à quoi ils ressemblent pour l'instant :

La construction du CSSOM bloque le rendu de la page, par conséquent il nous faut charger les styles aussi tôt que possible dans l'arbre, les alléger au maximum et différer leur chargement lorsque c'est efficient.
stratégies d'optimisation du chargement de CSS
utiliser les règles @media
Les règles @media
spécifient une condition devant être remplie pour que le style soit chargé, par exemple "y a-t-il une résolution minimum ou maximum?" ou bien "est-ce destiné aux lecteurs d'écran?"
Les ordinateurs sont très puissants mais les terminaux mobiles le sont moins, c'est pourquoi il est important de ne pas les surcharger. Nous pourrions charger les styles relatifs aux mobiles d'abord, puis mettre une règle @media
pour les styles relatifs aux ordinateurs — même si cela n'empêcherait pas le chargement, cela empêcherait le blocage de notre page et l'utilisation de ressources utiles.
// Ce CSS sera chargé et bloquera le rendu de la page dans tous les cas. media="all" est la valeur par défaut et équivaut à ne pas déclarer de règle @media :
<link rel="stylesheet" href="mobile-styles.css" media="all">
// Sur les mobiles, ce CSS sera chargé en arrière-plan et n'interrompra pas le chargement de la page :
<link rel="stylesheet" href="desktop-styles.css" media="min-width: 590px">
// Une media query CSS qui ne fonctionne que pour l'impression papier :
<style>
@media print {
img {
display: none;
}
}
</style>
différer le chargement du CSS
Si vous avez des styles qui peuvent attendre pour être chargés et calculés après la première peinture, par exemple des styles relatifs à du contenu apparaissant sous la partie supérieure de la page, ou à du contenu qui n'est pas essentiel jusqu'à ce que la page devienne responsive, vous pouvez utiliser un script pour attendre le chargement de la page avant d'y ajouter le style.
<html>
<head>
<link rel="stylesheet" href="main.css">
</head>
<body>
<div class="main">
Important above the fold content.
</div>
<div class="secondary">
Below the fold content.
Stuff you won't see until after page loads and you scroll down.
</div>
<script>
window.onload = function () {
// load secondary.css
}
</script>
</body>
</html>
Voici un exemple de ce qu'on peut faire, par Jake Archibald, et un autre exemple par le site GiftOfSpeed.
réduire la spécificité
Le poids des fichiers est un obstacle, mais il n'est pas le seul : la complexité des calculs en est un autre et cette complexité s'accroît avec la spécificité.
// Sélecteurs plus spécifiques == bad
.header .nav .menu .link a.navItem {
font-size: 18px;
}
// Sélecteurs moins spécifiques == good
a.navItem {
font-size: 18px;
}
Ne chargez que ce dont vous avez besoin
Cela peut paraître évident, et pourtant si vous avez travaillé suffisamment longtemps dans le front end vous savez qu'un des principaux problèmes avec CSS est l'imprévisibilité liée à la suppression de contenu — imprévisilité qui entraîne l'expansion continue de votre CSS.
Pour réduire votre CSS autant que possible, utilisez des outils tels que le package uncss ou si vous cherchez une alternative web, faites une petite recherche, ce n'est pas le choix qui manque.
Étape 3 — JavaScript
Le navigateur continue à construire ses noeuds DOM/CSSOM jusqu'à ce qu'il trouve des noeuds JavaScript, par exemple dans des scripts externes ou inline.
// Un script externe
<script src="app.js"></script>
// Un script interne
<script>
alert("Oh, hello");
</script>
Notre script pourrait avoir besoin d'accéder ou de manipuler du HTML ou des styles antérieurement définis, par conséquent nous devons attendre qu'ils soient tous construits.
Le navigateur doit donc stopper son analyse syntaxique des noeuds, achever la construction du CSSOM, exécuter le script, puis poursuivre. JavaScript est appelé "parser blocking", bloqueur d'analyse syntaxique, pour cette raison.
Les navigateurs ont un truc qui s'appelle "preload scanner" qui va scanner le DOM à la recherche de scripts et commencer leur pré-chargement, mais les scripts seront exécutés uniquement après que les noeuds CSS auront été construits.
Si nous avions le script suivant :
var button = document.querySelector("button");
button.style.fontWeight = "bold";
button.addEventListener("click", function () {
alert("Well done.");
});
Voici quel en serait l'effet sur notre DOM et notre CSSOM :

stratégies d'optimisation du chargement de JavaScript
L'optimisation des scripts est une des choses les plus importantes à faire — et l'une des choses que les sites web font le moins bien.
charger les scripts de manière asynchrone
En utilisant un attribut async
sur notre script, nous indiquons au navigateur qu'il peut continuer son travail et charger le script en parallèle mais sans bloquer le chargement de la page. Dès qu'il aura fini le chargement, le script pourra être exécuté.
<script src="async-script.js" async></script>
Cela signifie qu'il pourra être exécuté n'importe quand, ce qui conduit à deux problèmes évidents. Tout d'abord, il pourrait être exécuté bien après que la page soit chargée, donc si nous comptons sur lui pour l'UX, il y a un risque d'expérience dégradée. Ensuite, s'il est exécuté avant que la page ne soit chargée, nous ne pouvons pas savoir s'il aura accès aux bons éléments DOM/CSSOM et il pourrait donc ne pas fonctionner.

async
est bien pour les scripts qui n'affectent pas notre DOM ou le CSSOM, en particulier pour les scripts externes qui n'ont pas besoin de connaître notre code et ne sont pas essentiels à l'UX, comme les analytics ou le tracking. Cela dit, si vous avez un bon cas d'usage, utilisez le.
différer le chargement des scripts
defer
est assez similaire à async
en ce qu'il ne bloquera pas le chargement de notre page, toutefois il attendra pour être exécuté que le HTML ait été analysé, et il sera exécuté dans l'ordre d'apparition.

C'est une bonne option pour les scripts qui auront une incidence sur notre arbre de rendu sans être pour autant vitaux au contenu apparaissant dans la partie supérieure de la page, ou pour les scripts qui ont besoin d'autres scripts déjà exécutés.
<script src="defer-script.js" defer></script>
Voici une autre excellente option pour l'utilisation de la stratégie différée. Vous pourriez également utiliser addEventListener
. Si vous voulez en savoir plus, voici un bon endroit pour commencer.
// Tous les objets sont dans le DOM, et les images, scripts, liens et sous-frames ont été chargés.
window.onload = function () {
};
// Appelé quand le DOM est prêt, ce qui peut être avant les images et autres contenus externes.
document.onload = function () {
};
// The JQuery way
$(document).ready(function () {
});
Malheureusement, async
et defer
ne fonctionnent pas sur les scripts inline car par défaut les navigateurs les compilent et les exécutent dès qu'ils les rencontrent.
cloner des noeuds avant manipulation
Si (et seulement si) vous constatez un comportement indésirable lorsque vous avez des changements multiples dans le DOM, alors essayez ceci :
Il peut être plus efficace de cloner d'abord le noeud DOM entier, de faire des changements sur le clone, puis de remplacer l'original avec celui-ci, de façon à éviter des peintures successives et afin de diminuer l'utilisation de la mémoire. Cela évite également les changements 'tremblants' de votre page et les Flashes de Contenu Sans Style (FOUC, Flashes Of Unstyled Content)
// Manipuler efficacement un noeud en le clonant
var element = document.querySelector(".my-node");
var elementClone = element.cloneNode(true); // (true) clone aussi les noeuds enfants, (false) ne les clone pas
elementClone.textContent = "I've been manipulated...";
elementClone.children[0].textContent = "...efficiently!";
elementClone.style.backgroundColor = "green";
element.parentNode.replaceChild(elementClone, element);
Soyez prudents lorsque vous clonez, parce qu'on ne clone pas les eventListeners. Parfois cela peut être exactement ce que vous désirez. Nous avons utilisé cette méthode autrefois pour remettre à zéro les eventListeners quand ils n'appellaient pas les fonctions nommées et que nous ne disposions pas des méthodes .on()
et .off()
de jQuery.
Preload/Prefetch/Prerender/Preconnect
Ces attributs font grosso modo ce qu'ils annoncent, et ils le font bien. Mais ils sont assez récents et la compatibilité navigateurs n'est pas parfaite, ce qui signifie qu'ils ne sont pas des options vraiment utiles pour nous. Cela dit, si vous pouvez vous offrir ce luxe, voici des ressources intéressantes ici et là.
(publicité)
Étape 4 — Arbre de rendu
Une fois tous les noeuds lus et le DOM et le CSSOM prêts à être associés, le navigateur construit l'arbre de rendu. Si nous imaginons les noeuds comme des mots, et les Object Models comme des phrases, alors l'arbre de rendu est une page entière. Maintenant, le navigateur a tout ce dont il a besoin pour rendre la page.

Étape 5 — Layout
Nous arrivons maintenant à la phase de layout, où nous déterminons la dimension et la position de tous les éléments sur la page.

Étape 6 — Peinture
Et finalement, la phase de "peinture" (paint) où nous réalisons la trame de pixels (rasterize) sur l'écran.

Et tout ceci se produit généralement en l'espace de quelques secondes ou quelques dixièmes de secondes. Notre boulot est de rendre ce processus encore plus rapide.
Si les événements JavaScript modifient une partie de la page, cela entraîne une redéfinition de l'arbre de rendu et nous oblige à repasser par les étapes Layout et Peinture. Les navigateurs modernes sont suffisamment malins pour ne réaliser qu'une révision partielle, cependant nous ne pouvons pas compter sur l'efficacité ou la performance de ce processus.
Cela dit, il est clair que JavaScript est basé sur des événement du côté client, et nous voulons qu'il manipule notre DOM, c'est exactement ce qu'il va faire — mais nous allons limiter les effets de ces opérations sur la performance.
Parvenus à ce stade, vous en savez assez pour apprécier cette présentation de Tali Garsiel. Elle date de 2012, mais le contenu est toujours exact. Le paper très complet qu'elle a écrit sur le sujet peut être lu ici.
Si vous aimez ce que vous avez lu jusqu'ici mais avez encore soif d'apprendre, votre bible sera la spécification HTML5. Mais nous n'avons pas tout à fait terminé ! Restez avec moi encore quelques instants, nous allons découvrir pourquoi il nous faut faire tout cela.
Comment le navigateur fait ses appels au réseau
Dans cette deuxième partie, nous allons comprendre comment nous pouvons efficacement transférer au navigateur les données requises pour rendre notre page.
Quand le navigateur fait une requête vers une URL, notre serveur renvoie du HTML. Nous allons commencer par un contenu très simple et augmenter progressivement la complexité.
Admettons que nous ayons ce HTML dans notre page :
<!DOCTYPE html>
<html>
<head>
<title>The "Click the button" page</title>
</head>
<body>
<h1>
Button under construction...
</h1>
</body>
</html>
Nous devons ici introduire un nouveau terme : le chemin critique de rendu (CRP : critical rendering path). Il signifie simplement le nombre d'étapes que le navigateur doit effectuer pour rendre notre page. Voici ce à quoi ressemble notre diagramme CRP pour l'instant.

Le navigateur fait une requête GET, il reste inactif (idle) jusqu'à ce que nous répondions avec les 1kb de HTML de notre page (il n'y a pas encore de CSS ni de JavaScript), et il est alors capable de construire le DOM et de rendre notre page.
chemin critique de rendu
Le premier des trois indicateurs de CRP est la longueur du chemin. Nous devons la réduire au strict minimum.
Le navigateur fait un aller-retour vers le serveur pour récupérer le HTML dont il a besoin, et c'est tout ce dont il a besoin. Par conséquent notre longueur de chemin critique est 1, parfait.
Maintenant, relevons la difficulté d'un cran et ajoutons quelques styles internes et un peu de JavaScript.
<!DOCTYPE html>
<html>
<head>
<title>The "Click the button" page</title>
<style>
button {
color: white;
background-color: blue;
}
</style>
</head>
<body>
<button type="button">Click me</button>
<script>
var button = document.querySelector("button");
button.addEventListener("click", function () {
alert("Well done.");
});
</script>
</body>
</html>
Si nous examinons notre diagramme CRP, nous constatons quelques changements.

Nous avons deux étapes supplémentaires, construire le CSSOM et exécuter les scripts. Cependant, comme aucune requête externe ne doit être effectuée, ces deux étapes n'allonge pas notre longueur de chemin critique, yippie !
Mais attendez un instant, pas si vite. Remarquez que notre HTML pèse maintenant 2kb, ça doit avoir un impact quelque part.
bytes critiques
Notre deuxième indicateur entre en scène, ce sont les bytes critiques. On mesure ici le nombre de bytes devant être transférés pour rendre la page. Par là, on entend non pas tous les bytes qui seront chargés au final, mais ceux qui sont nécessaires pour rendre la page et faire qu'elle soit responsive.
Inutile de dire que nous devons également minimiser cet indicateur.
Vous êtes peut-être en train de vous dire "super, laissons carrément tomber les ressources externes", et là vous auriez tort. Cela peut être tentant à première vue, mais ça ne tient pas dès lors qu'on a des ressources importantes. En réalité, si mon équipe devait livrer une de nos pages en mettant inline ou interne tout ce dont elle a besoin, le chargement serait lourd et le navigateur n'est pas fait pour ça.
Vous pouvez consulter cet article intéressant sur l'effet de l'embarquement en ligne de tous les styles (tel que le recommande React) sur le chargement de la page. La taille du DOM quadruple, prend deux fois plus de temps à être monté et 50% de temps en plus pour être responsive. Totalement inacceptable.
Tenez compte du fait que les ressources externes peuvent être mises en mémoire cache, ce qui fait que lorsque vos utilisateurs visitent à nouveau vos pages, si elles utilisent les mêmes ressources, le navigateur utilisera ces ressources déjà présentes dans votre mémoire — et c'est excellent pour nous !
Alors montons encore d'un cran et allons chercher des ressources externes pour nos styles et pour nos scripts. Remarquez que nous avons un fichier CSS externe, un fichier JavaScript externe et un fichier JavaScript externe async
.
<!DOCTYPE html>
<html>
<head>
<title>The "Click the button" page</title>
<link rel="stylesheet" href="styles.css" media="all">
<script type="text/javascript" src="analytics.js" async></script> // async
</head>
<body>
<button type="button">Click me</button>
<script type="text/javascript" src="app.js"></script>
</body>
</html>
Notre diagramme CRP est maintenant :

Le navigateur va chercher notre page, il construit le DOM, et dès qu'il trouve une ressource externe le scanner de préchargement est lancé. Il commence à charger toutes les ressources externes qu'il peut trouver dans le HTML. Le CSS et le JavaScript ont la priorité par rapport aux autres ressources.
Il a choisi nos styles.css
et app.js
et crée un autre chemin critique pour aller les chercher. Il n'a pas choisi notre analytics.js
parce que nous lui avons donné un attribut async
. Le navigateur le téléchargera en priorité basse, mais comme il ne bloque pas le rendu de notre page, il n'est pas pris en compte dans le chemin critique.
fichiers critiques
Enfin, notre dernier indicateur, les fichiers critiques. C'est le nombre total de fichiers que le navigateur doit charger pour rendre notre page. Dans notre exemple, il y en a 3, le HTML, le CSS et le JavaScript — le script async
ne compte pas. Et bien sûr, plus les fichiers sont légers, mieux c'est.
retour à la longueur de chemin critique
Vous pensez peut-être qu'on est arrivés à la longueur maximale de chemin critique ? On aurait juste besoin de charger HTML, CSS et JavaScript pour rendre notre page, ce qu'on vient de faire en deux allers-retours.
limite de fichiers HTTP1
Mais la vie n'est pas si simple. Avec le protocole HTTP1, notre navigateur peut charger simultanément un nombre maximum de fichiers à partir d'un même domaine, ce nombre varie de 2 (pour les navigateurs très anciens) à 10 pour Edge, Chrome en traite 6.
Vous pouvez vérifier combien les navigateurs de vos utilisateurs peuvent charger simultanément sur le site developers corner (date 2014).
Vous pouvez contourner le problème en servant certaines ressources à partir de shadow domains, pour maximiser votre potentiel d'optimisation.
Mais attention : servez votre CSS critique uniquement depuis votre domaine, car la résolution DNS et le temps de latence à eux seuls vous feraient perdre tout possible avantage d'un autre scénario.
HTTP2
Si votre site utilise HTTP2 et que votre navigateur est compatible, alors vous pouvez complètement effacer ces limites. Malheureusement nous en sommes encore rarement là.
Pour le savoir, vous pouvez faire le test ici.
Limite du round trip TCP
Nouvel ennemi en vue !
La quantité maximale de données pouvant être tranférée en un aller-retour (round trip) est 14kb, et ceci est vrai de n'importe quelle requête incluant du HTML, du CSS et des scripts. C'est dû à la spécification TCP (Transmission Control Protocol, le protocole de contrôle de transmissions) qui vise à empêcher l'engorgement du réseau et la perte de paquets.
Si notre HTML dépasse les 14kb, nous devons faire un ou plusieurs allers-retours supplémentaires. Conclusion : ces ressources massives ont un réel impact car elles ajoutent des chemins à notre CRP.
The Big Kahuna
Et maintenant, la totale :
<!DOCTYPE html>
<html>
<head>
<title>The "Click the button" page</title>
<link rel="stylesheet" href="styles.css"> // 14kb
<link rel="stylesheet" href="main.css"> // 2kb
<link rel="stylesheet" href="secondary.css"> // 2kb
<link rel="stylesheet" href="framework.css"> // 2kb
<script type="text/javascript" src="app.js"></script> // 2kb
</head>
<body>
<button type="button">Click me</button>
<script type="text/javascript" src="modules.js"></script> // 2kb
<script type="text/javascript" src="analytics.js"></script> // 2kb
<script type="text/javascript" src="modernizr.js"></script> // 2kb
</body>
</html>
Oui je sais, ça fait beaucoup de CSS et de JavaScript pour un seul bouton, mais c'est un bouton important et il compte beaucoup pour nous, pas de jugement s'il vous plaît...
Notre HTML est minifié et GZippé comme il faut, il pèse 2kb, bien en-dessous de la limite des 14kb, donc il nous revient en un seul aller-retour de CRP et le navigateur se met à construire notre DOM avec le fichier critique, notre HTML.

Il prend un fichier CSS et grâce au preload scanner il identifie toutes les ressources externes (CSS et JavaScript) et fait une requête pour commencer à les télécharger. Et comme par hasard, le premier fichier CSS fait 14kb, tout juste la limite pour un aller-retour, donc c'est un CRP à lui tout seul.

Puis il continue à télécharger les ressources. Le reste pèse moins de 14kb donc on pourrait le faire en un seul aller-retour, mais il y a 7 ressources et comme notre site n'est pas sur HTTP2 et que nous utilisons Chrome, nous ne pouvons télécharger que 6 fichier en un aller-retour.

...et nous pouvons finalement télécharger notre dernier fichier et rendre le DOM.

Cela nous fait un CRP de 30kb de ressources critiques en 9 fichiers et 4 chemins critiques. Avec cette information et un peu de connaissance sur la latence de connection, on peut commencer à faire des estimations relativement précises sur la performance de la page pour un utilisateur donné.
(publicité)
stratégies d'optimisation
- Pagespeed Insights
Utilisez Insights pour identifier les problèmes de performance. Il y a également un onglet audit
dans Chrome DevTools.
- Apprenez à utiliser Chrome Developper Tools
DevTools est vraiment un outil génial. Je pourrais écrire un bouquin entier là-dessus, mais il existe déjà suffisamment de ressources, dont ce texte vraiment intéressant ( NdT : à la vitesse où évoluent les choses, certaines sections sont déjà obsolètes, mais Google renvoie vers l'information à jour).
- Faites votre build dans un bon environnement, vos tests dans un mauvais
Vous développez peut-être sur votre Macbook Pro avec un SSD de 1Tb et 32Gb de RAM, mais pour les tests vous devriez utiliser l'onglet network
de Chrome, si c'est le DevTool que vous utilisez, et simuler une connection à faible bande-passante avec un processeur (CPU) au charbon si vous voulez avoir un retour intéressant.
- Concaténez les ressources et fichiers
Dans les diagrammes CRP précédents, j'ai laissé de côté quelques points que nous n'avions pas besoin d'aborder tout de suite. Mais en gros, après réception de chaque fichier externe CSS et JavaScript, le navigateur construit le CSSOM et exécute des scripts. Donc même si vous arrivez à livrer plusieurs fichiers en un seul aller-retour, ils font tous perdre du temps et des ressources. Il est donc préférable de les combiner lorsque c'est pratique et de réduire la multiplicité des chargements.
- Styles internes pour le contenu au-dessus de la ligne de flottaison
Sur la question des CSS et JavaScript interne/inline, pour économiser des requêtes externes, les choses ne sont pas noires ou blanches, puisque l'argument de pouvoir mettre en mémoire cache les ressources externes est tout aussi fort.
Cependant, en ce qui concerne le contenu au-dessus de la ligne de flottaison (above the fold content, le contenu qui est en haut de page), les styles internes ont du sens puisqu'ils permettent un premier affichage sans attendre que l'ensemble des ressources soient chargées.
- Minifiez ou réduisez la taille des images
C'est basique, simple à faire et il y a le choix pour ce qui est des outils ( NdT : perso, j'utilise compressor en version lossy, sur les JPEG, PNG, SVG et GIF).
- Différez le chargement des images après celui de la page
Avec un petit JavaScript tout simple, vous pouvez différer le chargement des images apparaissant sous la ligne de flottaison, ou qui ne sont pas vitales pour la première interactivité. Vous trouverez une excellente stratégie dans cet article.
- Charger vos polices de caractères de manière asynchrone
Les polices de caractères prennent du temps à charger, et si vous le pouvez vous devriez utiliser une police avec des fallbacks, puis rendre progressivement vos polices et icônes. Ce n'est pas optimal, mais l'autre option est que votre page se charge sans texte, ce qu'on appelle le flash de texte invisible (Flash Of Invisible Text, FOIT).
- Avez-vous vraiment besoin de tout ce CSS/JavaScript ?
Vraiment ? N'y a-t-il pas un élément natif HTML qui puisse produire le comportement que vous souhaitez ? N'y a-t-il pas des styles ou des icônes que vous pourriez créer inline ? Par exemple avoir un SVG en ligne.
- Les CDN
Les CDN (Content Delivery Network) peuvent être utilisés pour servir vos ressources à partir d'un lieu physiquement plus proche de votre utilisateur, avec un temps de latence moindre, ce qui diminuera le temps de chargement.
Et voilà, vous en savez maintenant assez pour partir à la découverte et faire des recherches sur le sujet. Je vous recommande ce cours gratuit sur Udacity et la lecture de la documentation de Google sur l'optimisation.
Si vous voulez entrer encore plus en profondeur, un bon point de départ est ce livre gratuit (en anglais) High Performance Browser Networking par Ilya Grigorik.
Conclusion
Le chemin critique de rendu est très important, il nous donne quelques bonnes règles solides et logiques pour optimiser note site web. Les trois mesures qui comptent sont :
- Le nombre de bytes critiques
- Le nombre de fichiers critiques
- Le nombre de chemins critiques
Avec ce qui précède, vous devriez pouvoir mieux interpréter ce que Google Pagespeed Insights vous dit sur vos performances.
Dans un prochain article, j'espère pouvoir vous montrer un exemple réel de mise en pratique de tous ces principes.
(publicité)
Intéressé par la performance web ? Retrouvez une liste des meilleures ressources du web.
Tous les articles sur la performance web parus dans la Cascade.
Ressources complémentaires en français
Le chemin critique de rendu, par Ilya Grigorik (Google), entre beaucoup plus dans les détails que le présent article, tout en restant clair.
Les performances du chemin critique de rendu, excellent article de Thibault Mahé
Ressources complémentaires en anglais
Critical Rendering Path, par Patrick Sexton (Varvy)
Traduit avec l’aimable autorisation de Hackernoon et de l’auteur.
Copyright Hackernoon © 2017.
Sur l’auteur : Sanjay Purswani est Software Engineer chez comparethemarket.