Wiemy, że responsywność przewijania jest kluczowa dla zaangażowania użytkownika w witrynę na urządzeniu mobilnym, ale odsłuchi zdarzeń dotykowych często powodują poważne problemy z wydajnością przewijania. Chrome rozwiązuje ten problem, pozwalając słuchaczom zdarzeń dotykowych na pasywność (przekazywanie opcji {passive: true}
do addEventListener()
) oraz udostępniając interfejs API zdarzeń wskaźnika.
To świetne funkcje, które umożliwiają dodawanie nowych treści do modeli, które nie blokują przewijania, ale deweloperzy mają czasem problemy z ich zrozumieniem i wdrożeniem.
Uważamy, że internet powinien być szybki domyślnie, bez konieczności zrozumienia przez programistów skomplikowanych szczegółów działania przeglądarki. W Chrome 56 domyślnie detektory są pasywne w przypadkach, gdy jest to zgodne z zamiarem dewelopera. Wierzymy, że dzięki temu możemy znacznie poprawić wrażenia użytkowników, jednocześnie minimalizując negatywny wpływ na witryny.
W rzadkich przypadkach ta zmiana może spowodować niezamierzone przewijanie. Zwykle można to łatwo rozwiązać, stosując styl touch-action: none do elementu, w którym nie powinno być przewijania. Czytaj dalej, aby dowiedzieć się więcej o tym, jak sprawdzić, czy dotyczy to Ciebie, i co możesz zrobić.
Informacje ogólne: zdarzenia anulowane spowalniają stronę
Jeśli wywołasz preventDefault() w zdarzeniach touchstart
lub touchmove
, blokujesz przewijanie.
Problem polega na tym, że w większości przypadków detektory nie wywołają funkcji preventDefault()
, ale przeglądarka musi poczekać na zakończenie zdarzenia, aby się o tym przekonać.
Rozwiązaniem są „pasywne detektory zdarzeń” zdefiniowane przez deweloperów. Gdy dodasz zdarzenie dotyku z obiektem {passive: true}
jako 3 parametrem w obiekcie event, informujesz przeglądarkę, że odbiorca touchstart
nie wywoła metody preventDefault()
, a przeglądarka może bezpiecznie przeprowadzić przewijanie bez blokowania odbiornika. Na przykład:
window.addEventListener("touchstart", func, {passive: true} );
Interwencja
Naszą główną motywacją jest skrócenie czasu potrzebnego na zaktualizowanie wyświetlacza po dotknięciu ekranu przez użytkownika. Aby lepiej zrozumieć użycie zdarzeń touchstart i touchmove, dodaliśmy dane, które pozwalają określić, jak często występuje blokowanie przewijania.
Sprawdziliśmy odsetek zdarzeń dotykowych, które można anulować i które zostały wysłane do obiektu rdzeniowego (okna, dokumentu lub elementu body), i ustaliliśmy, że około 80% z nich jest teoretycznie pasywnych, ale nie zostało zarejestrowanych jako takie. Biorąc pod uwagę skalę tego problemu, zauważyliśmy, że istnieje świetna możliwość ulepszenia przewijania bez konieczności podejmowania przez programistów żadnych działań, ponieważ te zdarzenia są automatycznie „pasywne”.
W związku z tym zdefiniowaliśmy naszą interwencję w ten sposób: jeśli obiekt docelowy odbiornika dotyku w przypadku zdarzeń touchstart lub touchmove to window
, document
lub body
, domyślnie ustawiamy passive
na true
. Oznacza to, że kod taki jak:
window.addEventListener("touchstart", func);
staje się równoważny następującemu wyrażeniu:
window.addEventListener("touchstart", func, {passive: true} );
Teraz wywołania do preventDefault()
w słuchaczu będą ignorowane.
Wykres poniżej pokazuje czas, jaki zajmuje 1% najdłuższych przewijań od momentu dotknięcia ekranu do momentu jego zaktualizowania. Te dane dotyczą wszystkich witryn w Chrome na Androida. Zanim włączono interwencję, przewijanie 1% strony trwało nieco ponad 400 ms. W Chrome 56 Beta czas ten został skrócony do nieco ponad 250 ms, co oznacza spadek o około 38%. Mamy nadzieję, że w przyszłości wszystkie touchstart
i touchmove
będą domyślnie pasywne, co skróci czas ich działania do mniej niż 50 ms.

Uszkodzenia i wskazówki
W większości przypadków nie dochodzi do żadnych naruszeń. Jednak gdy dochodzi do awarii, najczęściej objawia się to przewijaniem, gdy tego nie chcesz. W rzadkich przypadkach deweloperzy mogą też zauważyć nieoczekiwane zdarzenia click (gdy brakuje elementu preventDefault()
w słuchaczu touchend
).
W Chrome 56 i nowszych wersjach w Narzędziach deweloperskich pojawi się ostrzeżenie, gdy wywołasz funkcję preventDefault()
w przypadku aktywnej interwencji.
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
Aplikacja może określić, czy jest to możliwe w przypadku danego urządzenia, sprawdzając, czy wywołanie funkcji preventDefault
miało jakikolwiek wpływ na właściwość defaultPrevented
.
Zauważyliśmy, że większość dotkniętych stron można stosunkowo łatwo naprawić, stosując w miarę możliwości właściwość touch-action w CSS. Jeśli chcesz zablokować przewijanie i powiększanie w przeglądarce w danym elemencie, zastosuj do niego touch-action: none
. Jeśli masz poziomy karuzelę, rozważ zastosowanie do niej touch-action: pan-y pinch-zoom
, aby użytkownik mógł normalnie przewijać w pionie i powiększać obraz. Właściwe zastosowanie atrybutu touch-action jest już konieczne w przypadku przeglądarek takich jak Edge na komputery, które obsługują zdarzenia Pointer, a nie Touch. W przypadku przeglądarki mobilnej Safari i starszych przeglądarek mobilnych, które nie obsługują akcji dotykowej, klasy do obsługi zdarzeń dotykowych muszą nadal wywoływać funkcję preventDefault
, nawet jeśli zostanie ona zignorowana przez Chrome.
W bardziej złożonych przypadkach może być konieczne użycie jednej z tych opcji:
- Jeśli
touchstart
wywołujepreventDefault()
, sprawdź, czy funkcja preventDefault() jest też wywoływana przez powiązane detektory touchend, aby nadal blokować generowanie zdarzeń kliknięcia i inne domyślne zachowania dotyku. - Ostatnia (i nie zalecana) forma przekazywania parametru
{passive: false}
do funkcji addEventListener() służy do zastąpienia domyślnego zachowania. Pamiętaj, że musisz użyć funkcji wykrywania, aby sprawdzić, czy User Agent obsługuje EventListenerOptions.
Podsumowanie
W Chrome 56 przewijanie staje się znacznie szybsze na wielu stronach internetowych. Jest to jedyny wpływ, jaki ta zmiana będzie miała na większość deweloperów. W niektórych przypadkach deweloperzy mogą zauważyć niezamierzone przewijanie.
Chociaż w przypadku Safari na urządzeniach mobilnych nadal jest to konieczne, witryny nie powinny polegać na wywoływaniu funkcji preventDefault()
w metodach touchstart
i touchmove
, ponieważ nie ma już gwarancji, że będą one obsługiwane w Chrome. Deweloperzy powinni zastosować właściwość CSS touch-action
do elementów, w których przypadku przewijanie i powiększanie powinno być wyłączone, aby powiadomić przeglądarkę przed wystąpieniem zdarzeń dotykowych.
Aby stłumić domyślne działanie kliknięcia (np. generowanie zdarzenia kliknięcia), wywołaj funkcję preventDefault()
w detektorze touchend
.