Optimiser l'interaction pour la page suivante

Découvrez comment optimiser l'interaction avec Next Paint sur votre site Web.

L'Interaction to Next Paint (INP) est une métrique Core Web Vitals stable qui évalue la réactivité globale d'une page aux interactions des utilisateurs en observant la latence de toutes les interactions pertinentes qui se produisent tout au long de la visite d'un utilisateur sur une page. La valeur INP finale correspond à l'interaction la plus longue observée (en ignorant parfois les anomalies).

Afin d'offrir une expérience utilisateur de qualité, les sites Web doivent s'efforcer d'avoir une "Interaction to Next Paint" de 200 millisecondes ou moins. Pour vous assurer d'atteindre cet objectif pour la plupart de vos utilisateurs, le 75e centile de chargements de pages, segmenté en fonction des appareils mobiles et des ordinateurs, constitue un bon seuil à mesurer.

Les bonnes valeurs INP sont inférieures ou égales à 200 millisecondes, les valeurs médiocres supérieures à 500 millisecondes et tous les éléments intermédiaires doivent être améliorés.

En fonction du site Web, il peut y avoir peu ou pas d'interactions (par exemple, des pages contenant principalement du texte et des images avec peu ou pas d'éléments interactifs). Ou, dans le cas de sites Web tels que les éditeurs de texte ou les jeux, il peut y avoir des centaines, voire des milliers d'interactions. Dans les deux cas, lorsque l'INP est élevé, l'expérience utilisateur est menacée.

Améliorer INP demande du temps et des efforts, mais l'avantage est une meilleure expérience utilisateur. Dans ce guide, nous allons explorer le moyen d'améliorer INP.

Déterminer ce qui cause une mauvaise INP

Avant de pouvoir corriger les interactions lentes, vous aurez besoin de données qui vous indiqueront si l'INP de votre site Web est médiocre ou doit être amélioré. Une fois que vous disposez de ces informations, vous pouvez passer au laboratoire pour commencer à diagnostiquer les interactions lentes et trouver une solution.

Identifier les interactions lentes sur le terrain

Dans l'idéal, votre parcours d'optimisation de l'INP commencera avec des données de terrain. Dans le meilleur des cas, les données de champ d'un fournisseur Real User Monitoring (RUM) vous fourniront non seulement la valeur INP d'une page, mais aussi des données contextuelles qui mettent en évidence l'interaction spécifique responsable de la valeur INP elle-même, si l'interaction s'est produite pendant ou après le chargement de la page, le type d'interaction (clic, pression de touche ou appui) et d'autres informations précieuses.

Si vous ne comptez pas sur un fournisseur RUM pour obtenir des données réelles, nous vous conseillons d'utiliser le rapport d'expérience utilisateur Chrome (CrUX) via PageSpeed Insights dans le guide des données de terrain de l'INP. CrUX est l'ensemble de données officiel du programme Core Web Vitals. Il fournit un résumé général des métriques de millions de sites Web, y compris l'INP. Cependant, CrUX ne fournit souvent pas les données contextuelles que vous obtiendrez d'un fournisseur RUM pour vous aider à analyser les problèmes. C'est pourquoi nous recommandons toujours aux sites de faire appel à un fournisseur de RUM lorsque cela est possible ou d'implémenter leur propre solution RUM pour compléter ce qui est disponible dans CrUX.

Diagnostiquer les interactions lentes dans l'atelier

Dans l'idéal, commencez les tests en laboratoire une fois que vous disposez de données de terrain qui suggèrent que les interactions sont lentes. En l'absence de données réelles, il existe des stratégies pour identifier les interactions lentes dans le laboratoire. Ces stratégies incluent le suivi des flux utilisateur courants et le test des interactions en cours de route, ainsi que les interactions avec la page pendant le chargement (lorsque le thread principal est souvent le plus actif) afin d'identifier les interactions lentes au cours de cette partie cruciale de l'expérience utilisateur.

Optimiser les interactions

Une fois que vous avez identifié une interaction lente et que vous pouvez la reproduire manuellement dans l'atelier, l'étape suivante consiste à l'optimiser. Les interactions peuvent être divisées en trois phases:

  1. Le délai d'entrée, qui commence lorsque l'utilisateur commence une interaction avec la page et se termine lorsque les rappels d'événement pour l'interaction commencent à s'exécuter.
  2. La durée du traitement, qui correspond au temps nécessaire pour que les rappels d'événement s'exécutent jusqu'à la fin.
  3. Le délai de présentation, qui correspond au temps nécessaire au navigateur pour présenter l'image suivante, qui contient le résultat visuel de l'interaction.

La somme de ces trois phases correspond à la latence totale des interactions. Chaque phase d'une interaction contribue à un certain temps à la latence totale des interactions. Il est donc important de savoir comment optimiser chaque partie de l'interaction pour qu'elle s'exécute le moins de temps possible.

Identifier et réduire le délai d'entrée

Lorsqu'un utilisateur interagit avec une page, la première partie de cette interaction est le délai d'entrée. En fonction des autres activités effectuées sur la page, les délais de saisie peuvent être très longs. Cela peut être dû à des activités sur le thread principal (par exemple, en raison du chargement, de l'analyse et de la compilation de scripts), de la gestion de la récupération, des fonctions de minuteur ou même d'autres interactions qui se succèdent rapidement et se chevauchent.

Quelle que soit la source du délai d'entrée d'une interaction, vous devez réduire au minimum ce délai d'entrée afin que les interactions puissent commencer à exécuter des rappels d'événements dès que possible.

Relation entre l'évaluation du script et les longues tâches au démarrage

Un aspect essentiel de l'interactivité dans le cycle de vie de la page est le démarrage. Lorsqu'une page se charge, elle s'affichera initialement. Toutefois, n'oubliez pas que ce n'est pas parce qu'une page s'affiche que son chargement est terminé. En fonction du nombre de ressources dont une page a besoin pour être pleinement fonctionnelle, il est possible que les utilisateurs essaient d'interagir avec la page pendant son chargement.

L'évaluation du script est une chose qui peut prolonger le délai d'entrée d'une interaction lors du chargement d'une page. Une fois qu'un fichier JavaScript a été récupéré sur le réseau, le navigateur a encore du travail avant que le code JavaScript puisse s'exécuter. Cela inclut l'analyse d'un script pour s'assurer que sa syntaxe est valide, sa compilation en bytecode, puis son exécution.

Selon la taille d'un script, ce travail peut introduire de longues tâches dans le thread principal, ce qui retarde le navigateur pour qu'il réponde aux autres interactions utilisateur. Pour que votre page reste réactive à l'entrée utilisateur lors de son chargement, il est important de comprendre ce que vous pouvez faire afin de réduire la probabilité de longues tâches pendant le chargement de la page afin que la page reste réactive.

Optimiser les rappels d'événements

Le délai d'entrée n'est que la première partie de ce que mesure INP. Vous devez également vous assurer que les rappels d'événement exécutés en réponse à une interaction de l'utilisateur peuvent être exécutés le plus rapidement possible.

Renvoyez souvent au thread principal

Le meilleur conseil général pour optimiser les rappels d'événements est d'y apporter le moins d'efforts possible. Cependant, votre logique d'interaction peut être complexe et vous ne pourrez peut-être que réduire légèrement le travail qu'ils effectuent.

Si c'est le cas pour votre site Web, vous pouvez ensuite essayer de diviser le travail des rappels d'événement en tâches distinctes. Cela évite que le travail collectif ne devienne une longue tâche qui bloque le thread principal, ce qui permet à d'autres interactions qui auraient autrement attendu le thread principal de s'exécuter plus tôt.

setTimeout est un moyen de diviser les tâches, car le rappel qui lui est transmis s'exécute dans une nouvelle tâche. Vous pouvez utiliser setTimeout seul ou extraire son utilisation dans une fonction distincte pour plus d'ergonomie.

Il est préférable de céder sans discernement plutôt que de ne pas du tout. Toutefois, il existe un moyen plus nuancé de céder au thread principal, et cela implique de ne renvoyer qu'immédiatement après un rappel d'événement qui met à jour l'interface utilisateur afin que la logique de rendu puisse s'exécuter plus tôt.

Rendre le travail d'affichage plus rapide

Une technique de rendement plus avancée consiste à structurer le code dans vos rappels d'événement afin de limiter les éléments exécutés à la logique requise pour appliquer des mises à jour visuelles à l'image suivante. Tout le reste peut être reporté à une tâche ultérieure. Cela permet non seulement de rendre les rappels légers et agiles, mais aussi d'améliorer le délai d'affichage des interactions en ne permettant pas aux mises à jour visuelles de bloquer le code de rappel d'événement.

Par exemple, imaginez un éditeur de texte enrichi qui met en forme le texte à mesure que vous saisissez du texte, mais qui met également à jour d'autres aspects de l'interface utilisateur en fonction de ce que vous avez écrit (comme le nombre de mots, la mise en évidence des fautes d'orthographe et d'autres commentaires visuels importants). En outre, il se peut que l'application doive également enregistrer ce que vous avez écrit afin de ne pas perdre votre travail si vous la quittez et y revenez.

Dans cet exemple, les quatre actions suivantes doivent se produire en réponse aux caractères saisis par l'utilisateur. Cependant, seul le premier élément doit être effectué avant que l'image suivante ne soit présentée.

  1. Modifiez la zone de texte avec le texte saisi par l'utilisateur et appliquez la mise en forme requise.
  2. Mettez à jour la partie de l'interface utilisateur qui affiche le nombre actuel de mots.
  3. Exécutez la logique pour vérifier les fautes d'orthographe.
  4. Enregistrez les modifications les plus récentes (en local ou dans une base de données distante).

Le code permettant d'effectuer cette opération peut se présenter comme suit:

textBox.addEventListener('input', (inputEvent) => {
  // Update the UI immediately, so the changes the user made
  // are visible as soon as the next frame is presented.
  updateTextBox(inputEvent);

  // Use `setTimeout` to defer all other work until at least the next
  // frame by queuing a task in a `requestAnimationFrame()` callback.
  requestAnimationFrame(() => {
    setTimeout(() => {
      const text = textBox.textContent;
      updateWordCount(text);
      checkSpelling(text);
      saveChanges(text);
    }, 0);
  });
});

La visualisation suivante montre comment le report des mises à jour non critiques jusqu'à la fin du frame suivant peut réduire la durée de traitement et donc la latence globale des interactions.

Représentation d'une interaction avec le clavier et de tâches ultérieures dans deux scénarios. Dans la figure du haut, la tâche essentielle de rendu et toutes les tâches ultérieures en arrière-plan s'exécutent de manière synchrone jusqu'à ce qu'il soit possible de présenter un frame. Dans la figure du bas, la tâche essentielle de rendu s'exécute d'abord, puis passe au thread principal pour présenter une nouvelle image plus tôt. Les tâches en arrière-plan s'exécutent ensuite.
Cliquez sur l'image ci-dessus pour afficher une version haute résolution.

Bien que l'utilisation de setTimeout() dans un appel requestAnimationFrame() dans l'exemple de code précédent soit certes un peu ésotérique, il s'agit d'une méthode efficace qui fonctionne dans tous les navigateurs pour garantir que le code non critique ne bloque pas le frame suivant.

Éviter le thrashing de mise en page

Le thrashing de mise en page, parfois appelé mise en page synchrone forcée, est un problème de performances d'affichage dans lequel la mise en page se produit de manière synchrone. Cela se produit lorsque vous mettez à jour des styles dans JavaScript, puis que vous les lisez dans la même tâche, et que de nombreuses propriétés en JavaScript peuvent entraîner le thrashing de mise en page.

Visualisation du thrashing de mise en page, comme indiqué dans le panneau "Performances" des outils pour les développeurs Chrome.
Exemple de thrashing de mise en page, comme indiqué dans le panneau "Performances" des outils pour les développeurs Chrome. Les tâches d'affichage impliquant un thrashing de mise en page sont signalées par un triangle rouge dans l'angle supérieur droit de la partie de la pile d'appel, souvent intitulé Recalculate Style (Recalculer le style) ou Layout (Mise en page).

Le thrashing de mise en page est un goulot d'étranglement des performances. En effet, en mettant à jour les styles, puis en demandant immédiatement les valeurs de ces styles en JavaScript, le navigateur est obligé d'effectuer un travail de mise en page synchrone, qu'il aurait pu attendre par la suite pour s'exécuter de manière asynchrone après l'exécution des rappels d'événements.

Réduire le délai de présentation

Le délai de présentation d'une marque d'interaction s'étend du moment où les rappels d'événement d'une interaction se sont terminés et jusqu'au moment où le navigateur est en mesure d'afficher l'image suivante, qui montre les modifications visuelles qui en résultent.

Réduire la taille du DOM

Lorsque le DOM d'une page est petit, le rendu se termine généralement rapidement. Toutefois, lorsque les DOM deviennent très volumineux, le rendu a tendance à s'adapter à l'augmentation de la taille du DOM. La relation entre le rendu et la taille du DOM n'est pas linéaire, mais les grands DOM nécessitent plus de travail que les petits DOM. Un grand DOM pose problème dans deux cas:

  1. Lors du rendu initial de la page, lorsqu'un grand DOM nécessite beaucoup de travail pour afficher l'état initial de la page.
  2. En réponse à une interaction de l'utilisateur, un DOM volumineux peut entraîner des mises à jour très coûteuses du rendu, ce qui augmente le temps nécessaire au navigateur pour afficher l'image suivante.

Gardez à l'esprit qu'il n'est pas toujours possible de réduire considérablement les grands DOM. Bien qu'il existe des méthodes pour réduire la taille du DOM, telles que l'aplatissement du DOM ou l'ajout au DOM lors des interactions utilisateur pour limiter la taille de votre DOM initial, ces techniques ne vont probablement pas loin.

Utiliser content-visibility pour effectuer le rendu différé des éléments hors écran

Pour limiter la quantité de travail d'affichage pendant le chargement de la page et le travail d'affichage en réponse aux interactions des utilisateurs, vous pouvez vous appuyer sur la propriété CSS content-visibility, qui équivaut à afficher des éléments d'affichage différé lorsqu'ils approchent de la fenêtre d'affichage. Bien que l'utilisation de content-visibility puisse nécessiter un peu de pratique, nous vous recommandons de vérifier si cela permet de réduire le délai d'affichage afin d'améliorer l'INP de votre page.

Tenir compte des coûts liés aux performances lors de l'affichage du code HTML à l'aide de JavaScript

Le code HTML doit être analysé, et une fois que le navigateur a fini d'analyser le code HTML dans un DOM, il doit lui appliquer des styles, effectuer des calculs de mise en page, puis effectuer le rendu de cette mise en page. Il s'agit d'un coût inévitable, mais la façon dont vous disposez pour l'affichage du code HTML est importante.

Lorsque le serveur envoie du code HTML, il arrive dans le navigateur sous forme de flux. Le traitement par flux signifie que la réponse HTML du serveur arrive en fragments. Le navigateur optimise la façon dont il gère un flux en analysant des fragments de ce flux de manière incrémentielle à leur arrivée et en les affichant bit par bit. Il s'agit d'une optimisation des performances, car le navigateur génère implicitement un rendement périodique et automatique lors du chargement de la page, ce qui est sans frais.

Même si la première visite d'un site Web implique toujours une partie du code HTML, une approche courante consiste à commencer par un minimum de code HTML, puis à utiliser JavaScript pour remplir la zone de contenu. Les mises à jour ultérieures de cette zone de contenu sont également le résultat d'interactions de l'utilisateur. C'est ce qu'on appelle généralement le modèle de l'application monopage (SPA). L'un des inconvénients de ce modèle est que, lorsque vous affichez du code HTML avec JavaScript sur le client, vous obtenez non seulement le coût du traitement JavaScript nécessaire à la création de ce code HTML, mais aussi le navigateur ne donne aucun résultat tant qu'il n'a pas fini d'analyser et d'afficher ce code HTML.

Il est cependant essentiel de se rappeler que même les sites Web qui ne sont pas des applications monopages impliqueront probablement un rendu HTML via JavaScript suite aux interactions. Ce n'est généralement pas un problème, tant que vous n'affichez pas beaucoup de code HTML sur le client, ce qui peut retarder la présentation du frame suivant. Toutefois, il est important de comprendre les implications de cette approche sur les performances pour l'affichage du code HTML dans le navigateur, et l'impact de cette approche sur la réactivité de votre site Web par rapport aux entrées utilisateur si vous affichez beaucoup de code HTML via JavaScript.

Conclusion

L'amélioration de l'INP de votre site est un processus itératif. Lorsque vous corrigez une interaction lente sur le terrain, il y a de fortes chances que vous décidiez de déceler d'autres interactions lentes, surtout si votre site Web offre beaucoup d'interactivité, et que vous deviez également les optimiser.

La clé pour améliorer INP est la persistance. Avec le temps, vous pourrez faire en sorte que la réactivité de votre page atteigne un niveau où les utilisateurs seront satisfaits de l'expérience que vous leur proposez. De plus, lorsque vous développez de nouvelles fonctionnalités pour vos utilisateurs, il est fort probable que vous deviez suivre le même processus pour optimiser les interactions qui leur sont propres. Cela demandera du temps et des efforts, mais c'est du temps et des efforts bien dépensés.

Image principale d'Unsplash, de David Pisnoy, modifiée conformément à la licence Unsplash.