Défilement virtuel pour des interfaces haute performance
Affichez 500 000 lignes dans un navigateur et votre interface risque de geler, de saccader ou de planter. Bien que les navigateurs modernes puissent gérer de grands arbres DOM, les performances se dégradent souvent de manière spectaculaire à mesure que le nombre de nœuds augmente, en raison des coûts de mise en page, de calcul de style et de mémoire. Le défilement virtuel résout ce problème en n’affichant que ce que l’utilisateur peut réellement voir — et cette seule contrainte change radicalement les performances des interfaces riches en données.
Points clés à retenir
- Le défilement virtuel n’affiche que les éléments visibles dans la zone d’affichage (viewport) plus une petite marge tampon, maintenant le nombre de nœuds DOM constant quelle que soit la taille du jeu de données.
- Il fonctionne en calculant les indices visibles à partir de
scrollTop, en affichant ces éléments et en utilisant des éléments de remplissage pour simuler la hauteur totale défilable. - Des hauteurs d’éléments fixes simplifient l’implémentation. Les hauteurs dynamiques nécessitent une mise en cache des mesures et une correction minutieuse de la position de défilement.
- La recherche native du navigateur (Ctrl+F), l’accessibilité et la stabilité de la position de défilement nécessitent tous une attention particulière dans les listes virtualisées.
- Des bibliothèques matures existent pour React, Angular et Vue — développer from scratch est rarement nécessaire en production.
Qu’est-ce que le défilement virtuel (et pourquoi ce n’est pas le défilement infini) ?
Le défilement virtuel (également appelé virtualisation de liste ou windowing) n’affiche que les éléments actuellement visibles dans la zone d’affichage, plus une petite marge tampon au-dessus et en dessous. Lorsque l’utilisateur fait défiler, les éléments quittant la zone d’affichage sont retirés du DOM et de nouveaux sont insérés à leur place. L’ensemble des données n’entre jamais complètement dans le DOM.
Cela diffère fondamentalement du défilement infini. Le défilement infini ajoute des éléments au DOM au fur et à mesure du défilement — la liste continue de croître. Le défilement virtuel échange les éléments, maintenant le nombre de nœuds DOM à peu près constant quelle que soit la taille du jeu de données.
La différence pratique est significative. Une liste naïvement affichée de 100 000 éléments pourrait créer plus de 100 000 nœuds DOM en mémoire. Une liste virtualisée du même jeu de données pourrait ne contenir que 50 à 80 nœuds à tout moment donné.
Comment fonctionnent conceptuellement les listes virtualisées
Le mécanisme repose sur quelques idées simples qui fonctionnent ensemble :
La fenêtre de visualisation. Vous donnez au conteneur de défilement une hauteur fixe. Cela définit combien d’éléments sont visibles à la fois — appelons cela visibleCount = Math.ceil(containerHeight / itemHeight).
Calcul d’index. Lorsque l’utilisateur fait défiler, vous lisez scrollTop pour déterminer quel élément se trouve en haut de la zone visible : startIndex = Math.floor(scrollTop / itemHeight). L’index de fin suit : endIndex = startIndex + visibleCount.
Illusion de position de défilement. Si vous n’affichez que 50 éléments, la barre de défilement refléterait une liste minuscule. Pour simuler la hauteur totale, vous placez un élément de remplissage vide au-dessus des éléments affichés (hauteur = startIndex × itemHeight) et un autre en dessous (hauteur = espace restant). La barre de défilement se comporte comme si l’ensemble des données était présent.
Overscan (marge tampon). N’afficher que les éléments exactement visibles provoque un effet d’apparition soudaine désagréable lors d’un défilement rapide. L’overscan affiche quelques lignes supplémentaires au-dessus et en dessous de la zone d’affichage — généralement 5 à 10 éléments, selon le cas d’usage — afin que les éléments soient déjà dans le DOM avant de glisser dans la vue.
Hauteurs d’éléments fixes vs. dynamiques
La virtualisation à hauteur fixe est simple et fiable. Chaque calcul est une arithmétique simple.
Les hauteurs dynamiques sont nettement plus difficiles. Vous devez soit mesurer chaque élément après le rendu et mettre en cache ces mesures, soit estimer les hauteurs à l’avance et les corriger après mesure. Les deux approches ajoutent de la complexité et peuvent causer une instabilité de la position de défilement si elles ne sont pas gérées avec soin. Si votre cas d’usage le permet, les hauteurs fixes valent la peine d’être conçues.
Discover how at OpenReplay.com.
Compromis réels à anticiper
Le défilement virtuel n’est pas gratuit. Quelques éléments se cassent ou nécessitent un travail supplémentaire :
- La recherche de texte du navigateur (Ctrl+F) cesse de fonctionner de manière fiable car la plupart du contenu n’est pas dans le DOM. Vous devrez implémenter votre propre recherche.
- L’accessibilité nécessite de l’attention. Appliquez
role="list",role="feed"ourole="grid"au conteneur. Vous pouvez utiliser des attributs commearia-setsizeetaria-posinsetpour que les technologies d’assistance puissent comprendre la taille totale de la liste et la position de chaque élément. Maintenez une gestion du focus pour que la navigation au clavier ne se casse pas lorsque les éléments sont démontés. Une petite marge tampon d’overscan aide également les lecteurs d’écran à détecter qu’il existe plus de contenu. - La stabilité de la position de défilement devient délicate lorsque les données sont mises à jour dynamiquement — des éléments ajoutés ou supprimés au-dessus de la position de défilement actuelle peuvent provoquer des sauts désagréables.
Support de l’écosystème à travers les frameworks
Vous avez rarement besoin de construire cela from scratch en production. Des bibliothèques matures gèrent les cas limites :
- React : TanStack Virtual (headless, flexible) et react-window (léger, supporte les tailles fixes et variables avec une configuration supplémentaire)
- Angular : CDK Virtual Scroll est intégré dans le Angular Component Dev Kit
- Vue : vue-virtual-scroller couvre la plupart des modèles courants
Une alternative CSS à connaître : content-visibility: auto permet au navigateur d’ignorer le rendu du contenu hors écran sans JavaScript. Cela peut améliorer les performances de peinture sur des listes modérées, mais cela ne réduit pas le nombre de nœuds DOM et ne remplace pas la virtualisation complète sur de grands jeux de données.
Quand l’utiliser réellement
Le défilement virtuel ajoute de la complexité. Il en vaut la peine lorsque :
- Votre liste dépasse quelques centaines d’éléments et les performances de défilement sont visiblement dégradées
- Vous construisez des tableaux, des visualiseurs de logs, des flux ou des interfaces de type tableur
- L’utilisation de la mémoire est une contrainte (appareils mobiles, sessions de longue durée)
Pour les listes courtes, la pagination ou le simple lazy loading est souvent plus simple et suffisant.
Conclusion
Les utilisateurs n’ont pas besoin de 100 000 nœuds DOM — ils ont besoin de sentir qu’ils peuvent faire défiler 100 000 éléments. Le défilement virtuel offre cette sensation pour une fraction du coût de rendu. En n’affichant que la tranche visible d’un jeu de données et en échangeant les éléments au fur et à mesure que l’utilisateur fait défiler, vous maintenez le nombre de nœuds DOM bas, l’utilisation de la mémoire prévisible et les fréquences d’images fluides. Les compromis — Ctrl+F cassé, considérations d’accessibilité, gestion de la position de défilement — sont réels mais bien compris, et l’écosystème de bibliothèques à travers React, Angular et Vue gère la plupart d’entre eux prêts à l’emploi. Si votre liste est suffisamment grande pour nuire aux performances, la virtualisation est l’outil le plus efficace disponible.
FAQ
Oui, mais cela nécessite une attention particulière. La plupart des bibliothèques de virtualisation supposent un layout de liste à une seule colonne. Pour les layouts en grille, vous devez calculer ensemble les lignes et colonnes visibles, en tenant compte des éléments par ligne. TanStack Virtual supporte nativement la virtualisation en grille. Avec d'autres bibliothèques, vous devrez peut-être traiter chaque ligne comme un seul élément virtualisé contenant plusieurs cellules.
Les robots d'exploration des moteurs de recherche ne font généralement pas défiler le contenu, donc les éléments en dehors du rendu initial ne seront pas indexés. Si le SEO est important pour le contenu de votre liste, envisagez une sortie HTML paginée ou des alternatives adaptées aux robots. Si vous effectuez un rendu côté serveur, appliquez la virtualisation uniquement après l'hydratation côté client.
Cela signifie généralement que votre marge tampon d'overscan est trop petite ou que le rendu de vos éléments est trop lent. Augmentez le nombre d'overscan pour que davantage d'éléments hors écran soient pré-rendus. Vérifiez également si vos éléments de liste déclenchent des recalculs de mise en page coûteux ou chargent des images de manière synchrone. Simplifier les composants d'éléments et utiliser du contenu placeholder pour les images peut réduire considérablement les images vides.
Oui. Avant la navigation, enregistrez la valeur scrollTop actuelle et le startIndex correspondant dans l'état ou le stockage de session. Lorsque l'utilisateur revient, restaurez la position du conteneur de défilement à la valeur scrollTop enregistrée. La plupart des bibliothèques de virtualisation exposent une méthode scrollToIndex ou scrollToOffset qui rend cela simple à implémenter lors du remontage.
Understand every bug
Uncover frustrations, understand bugs and fix slowdowns like never before with OpenReplay — the open-source session replay tool for developers. Self-host it in minutes, and have complete control over your customer data. Check our GitHub repo and join the thousands of developers in our community.