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

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 :

  1. Utiliser notre HTML pour créer le DOM (Document Object Model).
  2. Utiliser notre CSS pour créer le CSSOM (CSS Object Model).
  3. Exécuter les scripts sur le DOM et le CSSOM.
  4. Combiner le DOM et le CSSOM pour former l'arbre de rendu (render tree).
  5. Utiliser cet arbre de rendu pour disposer les éléments (taille et position).
  6. Peindre tous les pixels.
schéma du rendu général

É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 :

un arbre, avec des noeuds et des branches: html, head, meta, link...

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 :

un arbre partant de body, branche h1 avec font-size associée, branche button avec background-color associée

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 :

combinaison de nos 2 arbres précédents, avec l'ajout d'un style supplémentaire bold, et d'un eventListener click sur le bouton

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.

chargement du DOM et du script, 2 cas

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.

chargement du DOM et du script différé

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 .

É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.

l'arbre de rendu

É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.

phase de layout

Étape 6 — Peinture

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

phase de peinture

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.

How browsers work internally - Tali Garsiel - Front-Trends 2012 from Front-Trends on Vimeo.

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.

Métrique CRP : Longueur 1, Fichiers 1, Bytes 1

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.

Métrique CRP : Longueur 2, Fichiers 2, Bytes 16kb

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.

Métrique CRP : Longueur 3, Fichiers 8, Bytes 28kb

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

Métrique CRP : Longueur 4, Fichiers 9, Bytes 30kb

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é.

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 :

  1. Le nombre de bytes critiques
  2. Le nombre de fichiers critiques
  3. 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.


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)


original paru le 9 février 2017 dans Hackernoon
Traduit avec l’aimable autorisation de Hackernoon et de l’auteur.
Copyright Hackernoon © 2017
.

Sur l’auteur : est Software Engineer chez comparethemarket.