Vitesse par défaut du défilement tactile

Dave Tapuska
Dave Tapuska

Nous savons que la réactivité du défilement est essentielle à l'engagement de l'utilisateur avec un site Web sur mobile. Cependant, les écouteurs d'événements tactiles entraînent souvent de sérieux problèmes de performances de défilement. Pour résoudre ce problème, Chrome a autorisé les écouteurs d'événements tactiles à être passifs (en transmettant l'option {passive: true} à addEventListener()) et en envoyant l'API Événements de pointeur. Il s'agit d'excellentes fonctionnalités pour intégrer de nouveaux contenus dans des modèles qui ne bloquent pas le défilement, mais les développeurs les trouvent parfois difficiles à comprendre et à adopter.

Nous pensons que le Web doit être rapide par défaut, sans que les développeurs n'aient besoin de comprendre les détails mystérieux du comportement des navigateurs. Dans Chrome 56, les écouteurs tactiles passifs par défaut sont définis par défaut dans les cas où cela correspond le plus souvent à l'intention du développeur. Nous sommes convaincus que cette pratique nous permettra d'améliorer considérablement l'expérience utilisateur, tout en ayant un impact négatif minimal sur les sites.

Dans de rares cas, cette modification peut entraîner un défilement involontaire. Ce problème est généralement résolu en appliquant un style action tactile : none à l'élément qui ne doit pas faire défiler l'écran. Poursuivez votre lecture pour découvrir comment déterminer si vous êtes concerné et ce que vous pouvez faire pour y remédier.

Arrière-plan: les événements annulables ralentissent le chargement de votre page

Si vous appelez preventDefault() dans les événements touchstart ou touchmove, vous empêchez le défilement. Le problème est que, la plupart du temps, les écouteurs n'appellent pas preventDefault(), mais le navigateur doit attendre la fin de l'événement pour s'en assurer. Les "écouteurs d'événements passifs" définis par le développeur permettent de résoudre ce problème. Lorsque vous ajoutez un événement tactile avec un objet {passive: true} comme troisième paramètre dans votre gestionnaire d'événements, vous indiquez au navigateur que l'écouteur touchstart n'appelle pas preventDefault() et que le navigateur peut effectuer le défilement en toute sécurité sans bloquer l'écouteur. Exemple :

window.addEventListener("touchstart", func, {passive: true} );

L'intervention

Notre principale motivation est de réduire le temps nécessaire à la mise à jour de l'écran une fois que l'utilisateur a appuyé dessus. Pour comprendre l'utilisation de "touchstart" et de "touchmove", nous avons ajouté des métriques permettant de déterminer la fréquence à laquelle le blocage du défilement se produisait.

En examinant le pourcentage d'événements tactiles annulables qui ont été envoyés à une cible racine (fenêtre, document ou corps), nous avons constaté qu'environ 80% de ces écouteurs sont conceptuellement passifs, mais n'étaient pas enregistrés en tant que tels. Compte tenu de l'ampleur du problème, nous avons remarqué que nous pouvions améliorer le défilement sans aucune action du développeur en rendant ces événements automatiquement "passifs".

Cela nous a amenés à définir notre intervention comme suit: si la cible d'un écouteur touchstart ou de touchmove est window, document ou body, passive est défini par défaut sur true. Cela signifie que du code tel que:

window.addEventListener("touchstart", func);

devient équivalent à:

window.addEventListener("touchstart", func, {passive: true} );

Les appels à preventDefault() dans l'écouteur seront désormais ignorés.

Le graphique ci-dessous indique le temps nécessaire pour le 1% supérieur de défilements entre le moment où l'utilisateur touche l'écran pour le faire défiler et le moment où l'affichage est mis à jour. Ces données concernent tous les sites Web dans Chrome pour Android. Avant l'activation de l'intervention, 1% des défilements prenaient un peu plus de 400 ms. Ce délai a été réduit à un peu plus de 250 ms dans Chrome 56 bêta, soit une réduction d'environ 38%. À l'avenir, nous espérons définir l'argument "passif" sur "true" par défaut pour tous les écouteurs touchstart et touchmove, pour que ce paramètre soit inférieur à 50 ms.

Graphique des 1% des meilleurs moments de visionnage

Casse et conseils

Dans la grande majorité des cas, aucune défaillance n'est observée. Toutefois, en cas de panne, le symptôme le plus courant est que le défilement se produit lorsque vous ne le souhaitez pas. Dans de rares cas, les développeurs peuvent également remarquer des événements de clic inattendus (lorsque preventDefault() était absente d'un écouteur touchend).

À partir de la version 56 de Chrome, les outils de développement consignent un avertissement lorsque vous appelez preventDefault() dans un événement où l'intervention est active.

touch-passive.html:19 Unable to preventDefault inside passive event listener due to target being treated as passive. See https://www.chromestatus.com/features/5093566007214080

Votre application peut déterminer si c'est effectivement le cas en vérifiant si l'appel de preventDefault a eu un effet via la propriété defaultPrevented.

Nous avons constaté que la grande majorité des pages concernées sont corrigées relativement facilement en appliquant la propriété CSS action tactile dans la mesure du possible. Si vous souhaitez empêcher tout défilement et zoom dans le navigateur d'un élément, appliquez-lui touch-action: none. Si vous utilisez un carrousel horizontal, envisagez d'y appliquer touch-action: pan-y pinch-zoom afin que l'utilisateur puisse toujours faire défiler l'écran verticalement et zoomer comme d'habitude. Il est déjà nécessaire d'appliquer correctement l'action tactile dans les navigateurs tels que Desktop Edge qui prend en charge les événements de pointeur, et non les événements tactiles. Pour Safari pour mobile et les navigateurs mobiles plus anciens qui ne sont pas compatibles avec l'action tactile, vos écouteurs tactiles doivent continuer à appeler preventDefault, même lorsqu'il sera ignoré par Chrome.

Dans les cas plus complexes, il peut être nécessaire de s'appuyer également sur l'un des éléments suivants:

  • Si votre écouteur touchstart appelle preventDefault(), assurez-vous que la méthodepreventDefault() est également appelée à partir des écouteurs tactiles associés pour continuer à supprimer la génération d'événements de clic et d'autres comportements d'appui par défaut.
  • En dernier (et déconseillé) transmettez {passive: false} à addEventListener() pour remplacer le comportement par défaut. Sachez que vous devrez détecter les fonctionnalités si l'user-agent prend en charge les EventListenerOptions.

Conclusion

Dans Chrome 56, le défilement démarre beaucoup plus rapidement sur de nombreux sites Web. C'est le seul impact que la plupart des développeurs remarqueront. Dans certains cas, les développeurs peuvent remarquer un défilement indésirable.

Bien que cela soit toujours nécessaire pour Safari pour mobile, les sites Web ne doivent pas s'appuyer sur l'appel de preventDefault() dans les écouteurs touchstart et touchmove, car cela n'est plus garanti dans Chrome. Les développeurs doivent appliquer la propriété CSS touch-action aux éléments pour lesquels le défilement et le zoom doivent être désactivés afin d'informer le navigateur avant tout événement tactile. Pour supprimer le comportement par défaut d'un appui (comme la génération d'un événement de clic), appelez preventDefault() dans un écouteur touchend.