ResizeObserver: il s'apparente à document.onresize pour les éléments.

ResizeObserver vous indique quand la taille d'un élément change.

Avant ResizeObserver, vous deviez associer un écouteur au resize du document pour être averti de toute modification des dimensions de la fenêtre d'affichage. Dans l'événement vous devez déterminer quels éléments ont été affectés par qui changent et appellent une routine spécifique pour réagir de manière appropriée. Si vous en avez besoin les nouvelles dimensions d'un élément après un redimensionnement, vous deviez appeler getBoundingClientRect() ou getComputedStyle(), ce qui peut entraîner une mise en page le thrashing si vous ne vous occupez pas de regrouper toutes vos lectures et toutes vos les opérations d'écriture.

Cela ne concernait même pas les cas où les éléments changent de taille sans fenêtre ayant été redimensionnée. Par exemple, ajouter de nouveaux enfants, définir une le style display de l'élément en none, ou des actions similaires peuvent modifier la taille de d'un élément, de ses frères ou sœurs ou de ses ancêtres.

C'est pourquoi la primitive ResizeObserver est utile. Il réagit aux changements taille des éléments observés, indépendamment de la cause du changement. Elle permet également d'accéder à la nouvelle taille des éléments observés.

Navigateurs pris en charge

  • Chrome: 64 <ph type="x-smartling-placeholder">
  • Edge: 79 <ph type="x-smartling-placeholder">
  • Firefox: 69 <ph type="x-smartling-placeholder">
  • Safari: 13.1. <ph type="x-smartling-placeholder">

Source

API

Toutes les API avec le suffixe Observer que nous avons mentionnées ci-dessus partagent une API simple la conception. ResizeObserver ne fait pas exception. Vous créez un objet ResizeObserver. et transmettre un rappel au constructeur. Le rappel reçoit un tableau de des objets ResizeObserverEntry (une entrée par élément observé), qui contient les nouvelles dimensions de l'élément.

var ro = new ResizeObserver(entries => {
  for (let entry of entries) {
    const cr = entry.contentRect;

    console.log('Element:', entry.target);
    console.log(`Element size: ${cr.width}px x ${cr.height}px`);
    console.log(`Element padding: ${cr.top}px ; ${cr.left}px`);
  }
});

// Observe one or multiple elements
ro.observe(someElement);

Quelques informations

Quels sont les éléments signalés ?

En général, un ResizeObserverEntry signale la zone de contenu d'un élément via une propriété appelée contentRect, qui renvoie un DOMRectReadOnly . La zone de contenu est la zone dans laquelle le contenu peut être placé. Il est la zone de bordure moins la marge intérieure.

Schéma du modèle de zone CSS.

Il est important de noter que si ResizeObserver rapporte à la fois les dimensions du contentRect et de la marge intérieure, il surveille uniquement contentRect. Ne confondez pas contentRect avec le cadre de délimitation de l'élément. La limite comme indiqué par getBoundingClientRect(), est la boîte qui contient le l'élément entier et ses descendants. Les fichiers SVG font exception à la règle, car ResizeObserver indique les dimensions du cadre de délimitation.

Depuis Chrome 84, ResizeObserverEntry possède trois nouvelles propriétés pour offrir plus des informations détaillées. Chacune de ces propriétés renvoie un ResizeObserverSize contenant une propriété blockSize et une propriété inlineSize. Ce Les informations concernent l'élément observé au moment où le rappel est invoqué.

  • borderBoxSize
  • contentBoxSize
  • devicePixelContentBoxSize

Tous ces éléments renvoient des tableaux en lecture seule, ils peuvent prendre en charge des éléments comportant plusieurs fragments, qui apparaissent dans à plusieurs colonnes. Pour l'instant, ces tableaux ne contiennent qu'un seul élément.

La prise en charge de ces propriétés par la plate-forme est limitée, mais Firefox compatible avec les deux premières.

Quand est-elle signalée ?

La spécification interdit que ResizeObserver traite tous les événements de redimensionnement avant la peinture et après la mise en page. Ainsi, le rappel d'un ResizeObserver devient le l'endroit idéal pour modifier la mise en page de votre page. Parce que ResizeObserver entre la mise en page et la peinture, cela n'invalide la mise en page, pas la peinture.

J'ai compris

Vous vous demandez peut-être ce qui se passe si je modifie la taille d'une vue observée. dans le rappel de ResizeObserver ? La réponse est: vous allez déclencher un autre appel au rappel. Heureusement, ResizeObserver a un pour éviter les boucles de rappel infinies et les dépendances cycliques. Les modifications ne seront traités dans le même cadre que si l'élément redimensionné est plus profondément dans le DOM que l'élément le plus superficiel traité dans le rappel précédent. Sinon, elles seront différées vers l'image suivante.

Application

ResizeObserver vous permet d'implémenter un élément par élément. des requêtes média. En observant les éléments, vous pouvez définir de manière impérative votre concevoir des points d’arrêt et modifier les styles d’un élément. Dans les exemple : le deuxième champ modifie l'arrondi de sa bordure en fonction de sa largeur.

const ro = new ResizeObserver(entries => {
  for (let entry of entries) {
    entry.target.style.borderRadius =
        Math.max(0, 250 - entry.contentRect.width) + 'px';
  }
});
// Only observe the second box
ro.observe(document.querySelector('.box:nth-child(2)'));

Autre exemple intéressant : la fenêtre de chat. Le problème qui se pose dans une mise en page de conversation typique de haut en bas est le positionnement du défilement. Pour éviter déconcerter l'utilisateur, il est utile que la fenêtre soit collée au bas de la fenêtre où s'affichent les derniers messages. De plus, tout type de mise en page (pensez à un téléphone qui passe du mode paysage au mode portrait, ou inversement). atteindre le même résultat.

ResizeObserver vous permet d'écrire un seul extrait de code qui se charge de les deux scénarios. Le redimensionnement de la fenêtre est un événement qu'un ResizeObserver peut capture par définition, mais appeler appendChild() redimensionne également cet élément (sauf si overflow: hidden est défini), car il doit libérer de l'espace pour les nouvelles éléments. C'est pourquoi il faut très peu de lignes pour atteindre l'objectif effet:

const ro = new ResizeObserver(entries => {
  document.scrollingElement.scrollTop =
    document.scrollingElement.scrollHeight;
});

// Observe the scrollingElement for when the window gets resized
ro.observe(document.scrollingElement);

// Observe the timeline to process new messages
ro.observe(timeline);

Plutôt sympa, non ?

À partir de là, je pourrais ajouter plus de code pour gérer le cas où l'utilisateur a fait défiler la page manuellement et que vous voulez vous en tenir à ce message lorsqu'un nouveau message entre en jeu.

Autre cas d'utilisation : tout type d'élément personnalisé utilisant sa propre mise en page. Avant le ResizeObserver, il n'existait aucun moyen fiable d'être notifié lorsque les dimensions changent afin que ses enfants puissent être disposés à nouveau.

Effets sur l'interaction avec la peinture suivante (INP)

L'Interaction to Next Paint (INP) est une métrique qui mesure la la réactivité globale d'une page aux interactions de l'utilisateur. Si l'INP d'une page se trouve dans les "bonnes" seuil, soit 200 de millisecondes ou moins. On peut dire qu'une page réagit de façon fiable les interactions de l'utilisateur avec elle.

Alors que le temps nécessaire aux rappels d'événement pour s'exécuter en réponse à une l'interaction utilisateur peut contribuer de manière significative à la latence totale d'une interaction, ce n'est pas le seul aspect d'INP à prendre en compte. INP tient également compte de la quantité de temps nécessaire pour que la prochaine peinture de l'interaction se produise. Il s'agit de la temps nécessaire au rendu nécessaire pour mettre à jour l'utilisateur interface en réponse à une interaction pour terminer.

En ce qui concerne ResizeObserver, c'est important, car le rappel qui une instance ResizerObserver s'exécute juste avant le rendu. Ce ce qui est prévu par la conception, car le travail effectué lors du rappel doit être traité ce travail nécessitera très probablement de modifier de l'interface utilisateur.

Assurez-vous d'effectuer aussi peu de tâches d'affichage que nécessaire dans un ResizeObserver. , car un rendu excessif peut entraîner des situations dans lesquelles le navigateur a du retard dans ses tâches importantes. Par exemple, si une interaction a qui entraîne l'exécution d'un rappel ResizeObserver, assurez-vous d'effectuer la pour que l'expérience soit la plus fluide possible:

  • Assurez-vous que vos sélecteurs CSS sont aussi simples que possible afin d'éviter le recalcul des styles est trop important. Les recalculs de style ont lieu juste avant la mise en page, et les sélecteurs CSS complexes retarder les opérations de mise en page.
  • Évitez d'effectuer des tâches dans votre rappel ResizeObserver qui peuvent déclencher ajustements forcés de la mise en page.
  • Le temps nécessaire pour mettre à jour la mise en page d'une page augmente généralement avec le le nombre d'éléments DOM sur une page. Bien que cela soit vrai, que les pages utilisent ou non ResizeObserver, le travail effectué dans un rappel ResizeObserver peut devenir à mesure que la complexité structurelle d'une page augmente.

Conclusion

ResizeObserver est disponible dans toutes les principales navigateurs et permet de surveiller efficacement les redimensionnements d'éléments au niveau d'un élément d'application. Veillez simplement à ne pas trop retarder l'affichage avec cette API puissante.