Elimina 300 ms di ritardo sugli eventi di clic in Safari mobile


88

Ho letto che Safari mobile ha un ritardo di 300 ms sugli eventi di clic dal momento in cui si fa clic sul collegamento / pulsante al momento in cui si attiva l'evento. Il motivo del ritardo è aspettare per vedere se l'utente intende fare doppio clic, ma dal punto di vista dell'esperienza utente attendere 300 ms è spesso indesiderabile.

Una soluzione per eliminare questo ritardo di 300 ms è utilizzare la gestione "tap" di jQuery Mobile. Sfortunatamente non ho familiarità con questo framework e non voglio caricare un framework di grandi dimensioni se tutto ciò di cui ho bisogno è una o due righe di codice che si applicano touchendnel modo giusto.

Come molti siti, il mio sito ha molti eventi di clic come questo:

$("button.submitBtn").on('click', function (e) {   
  $.ajaxSubmit({... //ajax form submisssion
});

$("a.ajax").on('click', function (e) {   
  $.ajax({... //ajax page loading
});

$("button.modal").on('click', function (e) {   
      //show/hide modal dialog
});

e quello che vorrei fare è eliminare il ritardo di 300 ms su TUTTI quegli eventi di clic utilizzando un singolo frammento di codice come questo:

$("a, button").on('tap', function (e) {
 $(this).trigger('click');
 e.preventDefault();
});

È un'idea cattiva / buona?



@Pointy grazie, potrebbe funzionare ...
tim peterson

"... ovviamente questo non è eccezionale dal punto di vista dell'esperienza utente." Sarei diffidente su questo assunto.
Oliver Moran

1
@OliverMoran, grazie per la correzione, ho appena modificato quella frase, vedi la domanda sopra ..
tim peterson

1
potrebbe essere una soluzione: stackoverflow.com/a/12969739/1491212
Armel Larcier

Risposte:


72

Ora alcuni browser mobili eliminano un ritardo del clic di 300 ms se si imposta la visualizzazione. Non è più necessario utilizzare soluzioni alternative.

<meta name="viewport" content="width=device-width, user-scalable=no">

Questo è attualmente supportato Chrome per Android , Firefox per Android e Safari per iOS

Tuttavia, su iOS Safari , il doppio tocco è un gesto di scorrimento su pagine non ingrandibili. Per questo motivo non possono rimuovere il ritardo di 300 ms . Se non riescono a rimuovere il ritardo su pagine non ingrandibili, è improbabile che lo rimuovano su pagine zoomabili.

I telefoni Windows mantengono anche il ritardo di 300 ms sulle pagine non ingrandibili, ma non hanno un gesto alternativo come iOS, quindi è possibile rimuovere questo ritardo come ha Chrome.Puoi rimuovere il ritardo su Windows Phone utilizzando:

html {
-ms-touch-action: manipulation;
touch-action: manipulation;
}

Fonte: http://updates.html5rocks.com/2013/12/300ms-tap-delay-gone-away

AGGIORNAMENTO 2015 dicembre

Fino ad ora, WebKit e Safari su iOS avevano un ritardo di 350 ms prima che i singoli tocchi attivassero collegamenti o pulsanti per consentire alle persone di ingrandire le pagine con un doppio tocco. Chrome ha cambiato questo un paio di mesi fa già utilizzando un algoritmo più intelligente per rilevarlo e WebKit seguirà con un approccio simile . L'articolo fornisce alcune ottime informazioni su come i browser funzionano con i gesti tattili e su come i browser possono ancora diventare molto più intelligenti di quanto non siano oggi.

AGGIORNAMENTO 2016 marzo

In Safari per iOS, il tempo di attesa di 350 ms per rilevare un secondo tocco è stato rimosso per creare una risposta "tocco rapido". Questa opzione è abilitata per le pagine che dichiarano un viewport con width = device-width o user-scalable = no. Gli autori possono anche scegliere di eseguire il tocco rapido su elementi specifici utilizzando il CSS touch-action: manipulationcome documentato qui (scorri verso il basso fino all'intestazione "Stile comportamento tocco rapido") e qui .


In realtà, ci sono eventi touch per WP: stackoverflow.com/questions/13396297/…
Cedric Reichenbach

1
Sì, che è controllato da -ms-touch-action come ho scritto nel mio post.
NoName Fornito il

1
Il problema persiste su iOS quando si esegue l'applicazione dalla home page (standalone). Se qualcuno ha trovato una soluzione decente per questo, sarebbe molto gradito
Miguel Guardo

1
L'impostazione dei valori dell'azione tattile sulla manipolazione si avvicina di più alle prestazioni desiderate, ma come affermato in precedenza da @MiguelGuardo, l'effetto viene perso una volta aggiunta la pagina Web alla schermata principale in iOS come app autonoma.
T. Steele

Può essere che qualcuno può hackerare UIWebView - stackoverflow.com/questions/55155560/...
Eazy

43

Questo plugin -FastClick sviluppato dal Financial Times lo fa perfettamente per te!

Assicurati però di aggiungere event.stopPropagation();e / o event.preventDefault();direttamente dopo la funzione clic, altrimenti potrebbe essere eseguita due volte come ha fatto per me, ovvero:

$("#buttonId").on('click',function(event){
    event.stopPropagation(); event.preventDefault();
   //do your magic

});

3
Questo non è perfetto se stai usando jquery mobile (versione 1.3.2 comunque), interrompe la chiusura del widget del pannello github.com/jquery/jquery-mobile/issues/6440
ryan0

that event.stopPropagation () è esattamente il motivo per cui sono arrivato su questa pagina in primo luogo. Funziona perfettamente, grazie!
Lukas

@Jonathan fastclickfa la sua magia solo sui dispositivi touch che hanno un problema di ritardo (altrimenti viene bypassato automaticamente ). Tuttavia, la semplice aggiunta di stopPropagation& preventDefaultdopo ogni clic potrebbe avere effetti collaterali indesiderati su tutti i gestori di eventi in tutti i browser.
utente

17

so che questo è vecchio ma non puoi semplicemente provare per vedere se "touch" è supportato nel browser? Quindi creare una variabile che sia "touchend" o "clic" e utilizzare quella variabile come evento che viene associato al tuo elemento?

var clickOrTouch = (('ontouchend' in window)) ? 'touchend' : 'click';
$('#element').on(clickOrTouch, function() {
    // do something
});

In questo modo l'esempio di codice verifica se l'evento "touchend" è supportato nel browser e in caso contrario utilizziamo l'evento "click".

(Modifica: cambiato "touchend" in "ontouchend")


Grazie, mi piace la semplicità di questo. Mi piacerebbe che gli altri parlassero delle sue possibili insidie.
tim peterson

4
l'evento touchend non può sostituire l'evento click a causa di ciò che @Andreas Köberle spiega nella sua risposta. Ad esempio, se scorri e il dito si ferma su un pulsante, verrà attivato il collegamento ...
adriendenat

Questa è una fantastica soluzione leggera senza dover includere una grossa libreria aggiuntiva di cose solo per eliminare il ritardo. Vorrei poter votare 5 volte su questo! (fintanto che non sei preoccupato per lo scenario di scorrimento!)
tonejac

2
Per computer / browser con supporto per eventi tocco e clic, questa è una cattiva soluzione.
Alexander O'Mara

1
Alcuni dispositivi supportano eventi di tocco e clic e desideri che entrambi si attivino in situazioni diverse. Abbiamo riscontrato situazioni in cui alcune finestre o tablet Android dotati di mouse ovviamente attivano un evento clic quando fai clic su una cosa, ma attiveranno anche eventi tocco quando tocchi. Ciò significava che dovevi ascoltare entrambi gli eventi. Come ulteriore fattore di complicazione, alcuni dispositivi sintetizzano un evento clic quando si tocca, quindi l'ascolto di entrambi su quei dispositivi potrebbe comportare l'attivazione del gestore di eventi due volte, a meno che non si stia attenti.
1800 INFORMAZIONI

12

Mi sono imbattuto in un'alternativa estremamente popolare chiamata Hammer.js (pagina Github) che penso sia l'approccio migliore.

Hammer.js è una libreria touch più completa (ha molti comandi di scorrimento) rispetto a Fastclick.js (risposta più votata).

Attenzione però: lo scorrimento veloce sui dispositivi mobili tende a bloccare davvero l'interfaccia utente quando si utilizza Hammer.js o Fastclick.js. Questo è un grosso problema se il tuo sito ha un newsfeed o un'interfaccia in cui gli utenti scorreranno molto (sembrerebbe come la maggior parte delle app web). Per questo motivo, al momento non sto utilizzando nessuno di questi plugin.


2
Non usare Hammerjs. Ha alcuni seri problemi, ad esempio: github.com/EightMedia/hammer.js/issues/388 github.com/EightMedia/hammer.js/issues/366 Almeno non usarlo finché non vengono risolti
Adonis K. Kakoulidis

2

In qualche modo, disabilitare lo zoom sembra disabilitare questo piccolo ritardo. Ha senso, dato che il doppio tocco non è più necessario.

Come posso "disabilitare" lo zoom su una pagina web mobile?

Ma tieni presente l'impatto sull'usabilità che ciò avrà. Può essere utile per le pagine web progettate come app, ma non dovrebbe essere utilizzato per pagine "statiche" di uso generale IMHO. Lo uso per un progetto di animali domestici che necessita di bassa latenza.


1

Purtroppo non esiste un modo semplice per farlo. Quindi il solo utilizzo touchstarto touchendti lascerà con altri problemi come se qualcuno inizi a scorrere quando fai clic su un pulsante, ad esempio. Usiamo zepto per un po 'e anche con questo framework davvero buono ci sono alcuni problemi che sono emersi nel tempo. Molti di loro sono chiusi , ma sembra non sia un campo di semplice soluzione.

Abbiamo questa soluzione per gestire globalmente i clic sui link:

   $(document.body).
    on('tap', 'a',function (e) {
      var href = this.getAttribute('href');
      if (e.defaultPrevented || !href) { return; }
      e.preventDefault();
      location.href= href;
    }).
    on('click', 'a', function (e) {
      e.preventDefault();
    });

- @ Andreas, grazie quindi consiglieresti di non utilizzare la tapsoluzione generale che ho pubblicato e di considerare gli tapeventi elemento per elemento?
tim peterson

No, non è questo il punto. Il punto non è cercare di costruire una tapsoluzione da soli. Aggiornerò la mia risposta.
Andreas Köberle

- @ Andreas, grazie per la tua risposta, molti eventi di clic sono AJAX quindi l'evento predefinito è già prevenuto. Ti dispiacerebbe aggiornare la tua risposta per gestire anche questo? Sembrerebbe che la mia tapsoluzione generale sarebbe uguale alla tua in questo caso?
tim peterson

1

Ho cercato un modo semplice senza jquery e senza libreria fastclick. Questo funziona per me:

var keyboard = document.getElementById("keyboard");
var buttons = keyboard.children;
var isTouch = ("ontouchstart" in window);
for (var i=0;i<buttons.length;i++) {
    if ( isTouch ) {
        buttons[i].addEventListener('touchstart', clickHandler, false);         
    } else {
        buttons[i].addEventListener('click', clickHandler, false);          
    }
}

0

Solo per fornire alcune informazioni extra.

Su iOS 10, <button>i messaggi sulla mia pagina non potevano essere attivati ​​continuamente. C'era sempre un ritardo.

Ho provato fastclick / Hammer / tapjs / sostituzione del clic con touchstart, tutto fallito.

AGGIORNAMENTO: il motivo sembra essere che il pulsante è troppo vicino al bordo! spostalo vicino al centro e il ritardo sparisce!


0

Dovresti dichiarare esplicitamente la modalità passiva :

window.addEventListener('touchstart', (e) => {

    alert('fast touch');

}, { passive : true});

0

In jQuery puoi associare l'evento "touchend", il codice di attivazione della strega immediatamente dopo il tocco (è come un tasto sulla tastiera). Testato sulle attuali versioni di tablet Chrome e Firefox. Non dimenticare anche il "clic", per i tuoi laptop touch screen e dispositivi desktop.

jQuery('.yourElements').bind('click touchend',function(event){

    event.stopPropagation();
    event.preventDefault();

	// everything else
});

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.