Scorrimento al tocco veloce per impostazione predefinita

Dave Tapuska
Dave Tapuska

Sappiamo che la reattività dello scorrimento è fondamentale per coinvolgere l'utente con un sito web sui dispositivi mobili, ma i listener di eventi touch spesso causano gravi problemi di prestazioni dello scorrimento. Chrome si sta occupando di questo problema consentendo agli ascoltatori di eventi di tocco di essere passivi (trasmettendo l'opzione {passive: true} a addEventListener()) e inviando l'API Eventi puntatore. Si tratta di ottime funzionalità che consentono di inserire nuovi contenuti in modelli che non bloccano lo scorrimento, ma per gli sviluppatori a volte sono difficili da comprendere e adottare.

Riteniamo che il web debba essere veloce per impostazione predefinita, senza che gli sviluppatori debbano comprendere dettagli arcani del comportamento del browser. In Chrome 56 impostiamo per impostazione predefinita gli ascoltatori touch come passivi nei casi in cui il più delle volte ciò corrisponde all'intenzione dello sviluppatore. Riteniamo che in questo modo possiamo migliorare notevolmente l'esperienza utente senza avere un impatto negativo minimo sui siti.

In rari casi, questa modifica può causare lo scorrimento involontario. In genere, il problema viene facilmente risolto applicando uno stile touch-action: none all'elemento in cui non deve verificarsi lo scorrimento. Continua a leggere per i dettagli, come sapere se il problema ti riguarda e cosa puoi fare al riguardo.

Contesto: gli eventi annullabili rallentano la pagina

Se chiami preventDefault() negli eventi touchstart o touchmove, impedirai lo scorrimento. Il problema è che molto spesso i listener non chiamano preventDefault(), ma il browser deve attendere il termine dell'evento per esserne sicuri. I "Listener di eventi passivi" definiti dallo sviluppatore risolvono il problema. Quando aggiungi un evento touch con un oggetto {passive: true} come terzo parametro nel gestore di eventi, indichi al browser che il listener touchstart non chiamerà preventDefault() e che il browser può eseguire lo scorrimento in sicurezza senza bloccare il listener. Ad esempio:

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

L'intervento

La nostra motivazione principale è ridurre il tempo necessario per aggiornare il display dopo che l'utente lo ha toccato. Per capire l'utilizzo di touchstart e touchmove abbiamo aggiunto delle metriche per determinare la frequenza con cui si verifica il comportamento di blocco dello scorrimento.

Abbiamo esaminato la percentuale di eventi touch annullabili inviati a un target principale (finestra, documento o corpo) e abbiamo stabilito che circa l'80% di questi ascoltatori è concettualmente passivo, ma non è stato registrato come tale. Data la portata del problema, abbiamo notato un'ottima opportunità per migliorare lo scorrimento senza alcuna azione dello sviluppatore rendendo questi eventi automaticamente "passivi".

Questo ci ha spinto a definire il nostro intervento come segue: se il target di un listener touchstart o touchmove è window, document o body, per impostazione predefinita passive è impostato su true. Ciò significa che codice come:

window.addEventListener("touchstart", func);

diventa equivalente a:

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

Ora le chiamate a preventDefault() all'interno del listener verranno ignorate.

Il grafico seguente mostra il tempo impiegato dall'1% di scorrimenti dal momento in cui un utente tocca lo schermo per scorrere fino al momento in cui il display viene aggiornato. Questi dati riguardano tutti i siti web in Chrome per Android. Prima dell'abilitazione dell'intervento, l'1% degli scorrimenti richiedeva poco più di 400 ms. Ora il limite è stato ridotto a poco più di 250 ms in Chrome 56 Beta, con una riduzione di circa il 38%. In futuro ci auguriamo di rendere passivo il valore true come predefinito per tutti i listener touchstart e touchmove, riducendolo a meno di 50 ms.

Grafico dei migliori tempi di sroll dell'1%

Interruzione e indicazioni

Nella stragrande maggioranza dei casi, non si rilevano interruzioni. Tuttavia, quando si verifica una rottura, il sintomo più comune è lo scorrimento quando non lo desideri. In rari casi, gli sviluppatori potrebbero anche notare eventi clic imprevisti (quando preventDefault() non era presente in un listener touchend).

In Chrome 56 e versioni successive, DevTools registrerà un avviso quando chiami preventDefault() in un evento in cui l'intervento è attivo.

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

L'applicazione può determinare se sta raggiungendo questo valore in libertà controllando se la chiamata a preventDefault ha avuto effetto tramite la proprietà defaultPrevented.

Abbiamo riscontrato che la maggior parte delle pagine interessate viene risolta in modo relativamente semplice applicando la proprietà CSS touch-action quando possibile. Se vuoi impedire a tutto il browser di scorrere e eseguire lo zoom all'interno di un elemento, applica touch-action: none all'elemento. Se hai un carosello orizzontale, valuta la possibilità di applicare touch-action: pan-y pinch-zoom in modo che l'utente possa comunque scorrere in verticale ed eseguire lo zoom normalmente. È già necessaria l'applicazione corretta dell'azione touch sui browser, ad esempio desktop Edge, che supportano gli eventi puntatore e non gli eventi touch. Su Safari per dispositivi mobili e sui browser per dispositivi mobili meno recenti che non supportano l'azione touch, i listener touch devono continuare a chiamare preventDefault anche se verrà ignorato da Chrome.

Nei casi più complessi, potrebbe essere necessario fare affidamento anche su uno dei seguenti elementi:

  • Se il tuo listener touchstart chiama preventDefault(), assicurati chepreventDefault() venga chiamato anche dai listener di touchpoint associati per continuare a eliminare la generazione di eventi di clic e altri comportamenti di tocco predefiniti.
  • L'ultimo passaggio (e sconsigliato) di utilizzare {passive: false} ad signals() per eseguire l'override del comportamento predefinito. Tieni presente che dovrai rilevare tramite funzionalità se lo user agent supporta EventListenerOptions.

Conclusione

In Chrome 56, lo scorrimento si avvia molto più velocemente su molti siti web. Questo è l'unico impatto che la maggior parte degli sviluppatori noterà dopo questa modifica. In alcuni casi, gli sviluppatori potrebbero notare lo scorrimento involontario.

Sebbene sia comunque necessario farlo per Safari per dispositivi mobili, i siti web non devono fare affidamento sulla chiamata a preventDefault() all'interno degli ascoltatori touchstart e touchmove, in quanto questa operazione non è più garantita in Chrome. Gli sviluppatori devono applicare la proprietà CSS touch-action agli elementi in cui lo scorrimento e lo zoom devono essere disattivati per inviare una notifica al browser prima che si verifichino eventi di tocco. Per eliminare il comportamento predefinito di un tocco (ad esempio la generazione di un evento di clic), chiama preventDefault() all'interno di un listener touchend.