Nous savons que la réactivité du défilement est essentielle à l'engagement des utilisateurs avec un site Web sur mobile. Pourtant, les écouteurs d'événements tactiles provoquent souvent de graves problèmes de performances de défilement. Chrome a résolu ce problème en permettant aux écouteurs d'événements tactiles d'être passifs (en transmettant l'option {passive: true}
à addEventListener()
) et en distribuant l'API pointer events.
Ces fonctionnalités sont idéales pour intégrer de nouveaux contenus dans des modèles qui ne bloquent pas le défilement, mais les développeurs ont parfois du mal à les comprendre et à les adopter.
Nous pensons que le Web doit être rapide par défaut, sans que les développeurs aient besoin de comprendre les détails obscurs du comportement des navigateurs. Dans Chrome 56, nous définissons les écouteurs tactiles sur "passifs par défaut" dans les cas où cela correspond le plus souvent à l'intention du développeur. Nous pensons que ce faisant, nous pouvons grandement améliorer l'expérience utilisateur tout en minimisant l'impact négatif sur les sites.
Dans de rares cas, cette modification peut entraîner un défilement involontaire. Pour résoudre ce problème, il suffit généralement d'appliquer un style touch-action: none à l'élément où le défilement ne doit pas se produire. Lisez la suite pour en savoir plus, savoir si vous êtes concerné et découvrir ce que vous pouvez faire.
Contexte: les événements annulables ralentissent votre page
Si vous appelez preventDefault() dans les événements touchstart
ou touchmove
, vous empêchez le défilement.
Le problème est que, dans la plupart des cas, 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 résolvent 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'appellera 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} );
The Intervention
Notre motivation principale est de réduire le temps nécessaire pour mettre à jour l'écran après que l'utilisateur a touché l'écran. Pour comprendre l'utilisation de touchstart et de touchmove, nous avons ajouté des métriques pour déterminer la fréquence du comportement de blocage du défilement.
Nous avons examiné le pourcentage d'événements tactiles annulables envoyés à une cible racine (fenêtre, document ou corps) et déterminé qu'environ 80% de ces écouteurs sont conceptuellement passifs, mais qu'ils n'ont pas été enregistrés en tant que tels. Compte tenu de l'ampleur de ce problème, nous avons vu une excellente opportunité d'améliorer le défilement sans aucune action de la part du développeur en rendant ces événements automatiquement "passifs".
Nous avons donc défini notre intervention comme suit: si la cible d'un écouteur touchstart ou touchmove est window
, document
ou body
, nous définissons passive
sur true
par défaut. Cela signifie que le code suivant:
window.addEventListener("touchstart", func);
devient équivalent à:
window.addEventListener("touchstart", func, {passive: true} );
Les appels à preventDefault()
dans l'écouteur sont désormais ignorés.
Le graphique ci-dessous montre le temps nécessaire pour les 1% de défilements les plus fréquents, du moment où l'utilisateur appuie sur l'écran pour faire défiler l'écran jusqu'au 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 est désormais réduit à un peu plus de 250 ms dans la version bêta de Chrome 56, soit une réduction d'environ 38%. À l'avenir, nous espérons définir la valeur "true" pour la propriété passive par défaut pour tous les écouteurs touchstart
et touchmove
, ce qui réduira ce délai à moins de 50 ms.

Défaillances et conseils
Dans la grande majorité des cas, aucune rupture n'est observée. Toutefois, lorsque la rupture se produit, 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 manquant dans un écouteur touchend
).
Dans Chrome 56 et versions ultérieures, les outils de développement enregistrent 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 elle peut rencontrer ce problème dans la pratique 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 peuvent être corrigées relativement facilement en appliquant la propriété CSS touch-action dans la mesure du possible. Si vous souhaitez empêcher tout défilement et tout zoom dans un élément, appliquez-lui touch-action: none
. Si vous utilisez un carrousel horizontal, envisagez d'appliquer touch-action: pan-y pinch-zoom
afin que l'utilisateur puisse toujours faire défiler l'écran verticalement et faire un zoom comme d'habitude. L'application correcte de l'action tactile est déjà nécessaire sur les navigateurs tels que Edge pour ordinateur, qui acceptent les événements de pointeur et non les événements tactiles. Pour Safari mobile et les anciens navigateurs mobiles qui ne prennent pas en charge les actions tactiles, vos écouteurs tactiles doivent continuer à appeler preventDefault
, même s'ils sont ignorés par Chrome.
Dans des cas plus complexes, vous devrez peut-être également vous appuyer sur l'une des solutions suivantes:
- Si votre écouteur
touchstart
appellepreventDefault()
, assurez-vous que preventDefault() est également appelé à partir des écouteurs touchend associés pour continuer à supprimer la génération d'événements de clic et d'autres comportements par défaut de pression. - Dernière (et déconseillée) transmission de
{passive: false}
à addEventListener() pour remplacer le comportement par défaut. Notez que vous devrez détecter si l'User-Agent est compatible avec EventListenerOptions.
Conclusion
Dans Chrome 56, le défilement commence beaucoup plus rapidement sur de nombreux sites Web. Il s'agit du seul impact que la plupart des développeurs remarqueront suite à ce changement. Dans certains cas, les développeurs peuvent remarquer un défilement involontaire.
Bien qu'il soit toujours nécessaire de le faire pour Safari 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 qu'aucun événement tactile ne se produise.
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
.