Standardmäßig schnelles Scrollen durch Berührung

Tapuska
Dave Tapuska

Wir wissen, dass die Reaktionsfähigkeit beim Scrollen entscheidend für die Interaktion des Nutzers mit einer mobilen Website ist. Touch-Event-Listener verursachen jedoch oft erhebliche Probleme mit der Scrollleistung. In Chrome wurde das Problem behoben, indem Touch-Event-Listener passiv sein können (die Option {passive: true} wird an addEventListener() übergeben) und die Pointer Events API versendet. Dies sind großartige Funktionen, um neue Inhalte in Modelle zu integrieren, die das Scrollen nicht blockieren. Entwickler haben jedoch manchmal Schwierigkeiten, sie zu verstehen und zu übernehmen.

Wir sind der Meinung, dass das Web standardmäßig schnell sein sollte, ohne dass Entwickler komplexe Details zum Browserverhalten verstehen müssen. In Chrome 56 werden Touch-Listener standardmäßig auf passive gesetzt, wenn dies am häufigsten mit den Absichten des Entwicklers übereinstimmt. Wir sind der Meinung, dass wir so die Nutzererfahrung erheblich verbessern und die negativen Auswirkungen auf die Websites minimieren können.

In seltenen Fällen kann diese Änderung zu unbeabsichtigtem Scrollen führen. Dies lässt sich normalerweise leicht beheben, indem auf das Element, in dem kein Scrollen stattfinden sollte, der Stil Touchaktion: none angewendet wird. Lesen Sie weiter, um Einzelheiten zu erfahren, wie Sie feststellen können, ob Sie betroffen sind, und was Sie dagegen tun können.

Hintergrund: Stornierbare Ereignisse verlangsamen Ihre Seite.

Wenn Sie preventDefault() im touchstart oder im ersten touchmove-Ereignis aufrufen, verhindern Sie das Scrollen. Das Problem besteht darin, dass Listener in den meisten Fällen nicht preventDefault() aufrufen. Der Browser muss aber warten, bis das Ereignis abgeschlossen ist, um sich sicher zu sein. Entwicklerdefinierte "passive Event-Listener" lösen dieses Problem. Wenn Sie ein Touch-Ereignis mit einem {passive: true}-Objekt als dritten Parameter in Ihrem Event-Handler hinzufügen, teilen Sie dem Browser mit, dass der touchstart-Listener preventDefault() nicht aufruft und der Browser problemlos scrollen kann, ohne den Listener zu blockieren. Beispiel:

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

Die Intervention

Unsere Hauptmotivation besteht darin, die Zeit bis zur Aktualisierung des Displays zu verkürzen, nachdem der Nutzer das Display berührt hat. Um die Nutzung von „touchstart“ und „touchmove“ zu verstehen, haben wir Messwerte hinzugefügt, um zu ermitteln, wie häufig Scroll-Blockierungen auftreten.

Wir haben uns den Prozentsatz der abgebrochenen Touch-Ereignisse angesehen, die an ein Root-Ziel (Fenster, Dokument oder Text) gesendet wurden. Dabei haben wir festgestellt, dass etwa 80% dieser Listener konzeptionell passiv sind, aber nicht als solche registriert wurden. In Anbetracht des Umfangs dieses Problems haben wir eine große Chance erkannt, das Scrollen ohne Eingriff des Entwicklers zu verbessern, indem diese Ereignisse automatisch "passiv" werden.

Dies hat uns dazu veranlasst, unsere Maßnahme so zu definieren: Wenn das Ziel eines Touchstart- oder Touchmove-Listeners window, document oder body ist, wird passive standardmäßig auf true festgelegt. Das bedeutet, dass Code wie der folgende:

window.addEventListener("touchstart", func);

entspricht:

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

Aufrufe von preventDefault() im Listener werden jetzt ignoriert.

Das folgende Diagramm zeigt die Zeit, die die oberen 1% der Scrollvorgänge ab dem Zeitpunkt, an dem ein Nutzer den Bildschirm berührt, bis zur Aktualisierung des Bildschirms vergeht. Diese Daten gelten für alle Websites in Chrome für Android. Vor dem Aktivieren des Eingriffs dauerte 1% der Scrolls etwas mehr als 400 ms. Dieser Wert wurde in Chrome 56 Beta nun auf etwas mehr als 250 ms reduziert; eine Reduzierung um etwa 38%. Zukünftig möchten wir das passiv „true“ für alle touchstart- und touchmove-Listener standardmäßig auf unter 50 ms reduzieren.

Diagramm zu Sroll-Zeiten der obersten 1 %

Fehler und Anleitung

In den meisten Fällen wird kein Bruch beobachtet. Tritt das Problem jedoch auf, besteht das häufigste Symptom darin, dass gescrollt werden kann, wenn Sie es nicht möchten. In seltenen Fällen können Entwickler auch unerwartete Klickereignisse feststellen, wenn preventDefault() in einem touchend-Listener fehlte.

In Chrome 56 und höher wird in den Entwicklertools eine Warnung protokolliert, wenn du preventDefault() aufrufst und die Aufforderung aktiv ist.

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

Ihre Anwendung kann feststellen, ob dies in der Praxis passiert. Dazu wird geprüft, ob der Aufruf von preventDefault über die Property defaultPrevented Auswirkungen hatte.

Unserer Erfahrung nach lässt sich das Problem bei einer großen Mehrheit der betroffenen Seiten relativ einfach beheben, indem nach Möglichkeit die CSS-Eigenschaft touch-action angewendet wird. Wenn Sie das gesamte Scrollen und Zoomen im Browser innerhalb eines Elements verhindern möchten, wenden Sie touch-action: none darauf an. Bei einem horizontalen Karussell sollten Sie touch-action: pan-y pinch-zoom anwenden, damit der Nutzer weiterhin vertikal scrollen und wie gewohnt zoomen kann. Die korrekte Anwendung von Touch-Aktionen ist in Browsern wie Desktop Edge, die Zeigerereignisse und keine Touch-Ereignisse unterstützen, bereits erforderlich. Bei Safari für Mobilgeräte und älteren mobilen Browsern, die Touch-Aktionen nicht unterstützen, müssen Ihre Touch-Listener weiterhin preventDefault aufrufen, auch wenn sie von Chrome ignoriert werden.

In komplexeren Fällen ist möglicherweise auch eine der folgenden Optionen erforderlich:

  • Wenn der touchstart-Listener preventDefault() aufruft, muss „preventDefault()“ auch von zugehörigen Touchend-Listenern aufgerufen werden, damit die Generierung von Klickereignissen und andere standardmäßige Tippverhaltensweisen weiterhin unterdrückt werden.
  • Übergeben Sie zuletzt {passive: false} (nicht empfohlen) an addEventListener(), um das Standardverhalten zu überschreiben. Sie müssen mithilfe einer Funktion erkennen, ob der User-Agent EventListenerOptions unterstützt.

Fazit

In Chrome 56 beginnt das Scrollen auf vielen Websites wesentlich schneller. Dies ist die einzige Auswirkung, die die meisten Entwickler durch diese Änderung bemerken. In einigen Fällen bemerken Entwickler möglicherweise unbeabsichtigtes Scrollen.

Obwohl dies für mobile Safari weiterhin erforderlich ist, sollten Websites nicht darauf angewiesen sein, preventDefault() innerhalb von touchstart- und touchmove-Listenern aufzurufen, da dies in Chrome nicht mehr garantiert wird. Entwickler sollten die CSS-Eigenschaft touch-action auf Elemente anwenden, bei denen Scrollen und Zoomen deaktiviert sein sollten, um den Browser zu benachrichtigen, bevor Touch-Ereignisse auftreten. Wenn Sie das Standardverhalten eines Tippens (z. B. die Generierung eines Klickereignisses) unterdrücken möchten, rufen Sie preventDefault() in einem touchend-Listener auf.