Elimina el retraso de 300 ms en los eventos de clic en Safari móvil


89

He leído que Safari móvil tiene un retraso de 300 ms en los eventos de clic desde el momento en que se hace clic en el enlace / botón hasta que se activa el evento. La razón del retraso es esperar para ver si el usuario tiene la intención de hacer doble clic, pero desde una perspectiva de UX, esperar 300ms a menudo no es deseable.

Una solución para eliminar este retraso de 300 ms es utilizar el manejo de "tap" de jQuery Mobile. Desafortunadamente, no estoy familiarizado con este marco y no quiero cargar un marco grande si todo lo que necesito es una línea o dos de código que se aplique touchendde la manera correcta.

Como muchos sitios, mi sitio tiene muchos eventos de clic como este:

$("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
});

y lo que me gustaría hacer es deshacerme del retraso de 300ms en TODOS esos eventos de clic usando un solo fragmento de código como este:

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

¿Es una mala / buena idea?



@Pointy gracias, esto podría funcionar ...
tim peterson

"... obviamente esto no es genial desde una perspectiva de UX". Sería cauteloso con esta suposición.
Oliver Moran

1
@OliverMoran, gracias por la corrección, acabo de editar esa oración, vea la pregunta anterior ..
tim peterson

1

Respuestas:


73

Ahora, algunos navegadores móviles eliminan la demora de clic de 300 ms si configura la ventana gráfica. Ya no es necesario utilizar soluciones alternativas.

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

Actualmente, es compatible con Chrome para Android , Firefox para Android y Safari para iOS.

Sin embargo, en iOS Safari , tocar dos veces es un gesto de desplazamiento en páginas que no se pueden ampliar. Por esa razón, no pueden eliminar el retraso de 300 ms . Si no pueden eliminar el retraso en las páginas que no se pueden ampliar, es poco probable que lo eliminen en las páginas que se pueden ampliar.

Teléfonos Windows también retienen el retraso de 300 ms en páginas que no se pueden ampliar, pero no tienen un gesto alternativo como iOS, por lo que es posible eliminar este retraso como lo ha hecho Chrome.Puede eliminar el retraso en Windows Phone usando:

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

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

ACTUALIZACIÓN 2015 Diciembre

Hasta ahora, WebKit y Safari en iOS tenían un retraso de 350 ms antes de que un solo toque activara enlaces o botones para permitir que las personas acercaran las páginas con un doble toque. Chrome ya cambió esto hace un par de meses usando un algoritmo más inteligente para detectarlo y WebKit seguirá con un enfoque similar . El artículo ofrece una gran comprensión de cómo funcionan los navegadores con gestos táctiles y cómo los navegadores pueden volverse mucho más inteligentes de lo que son hoy.

ACTUALIZACIÓN Marzo 2016

En Safari para iOS, el tiempo de espera de 350 ms para detectar un segundo toque se ha eliminado para crear una respuesta de "toque rápido". Esto está habilitado para páginas que declaran una ventana gráfica con width = device-width o user-scalable = no. Los autores también pueden optar por el comportamiento de toque rápido en elementos específicos utilizando el CSS touch-action: manipulationcomo se documenta aquí (desplácese hacia abajo hasta el encabezado 'Comportamiento de toque rápido de estilo') y aquí .


En realidad, hay eventos táctiles para WP: stackoverflow.com/questions/13396297/…
Cedric Reichenbach

1
Sí, que está controlado por -ms-touch-action como escribí en mi publicación.
NoNameProvided

1
El problema persiste en iOS al ejecutar la aplicación desde la página de inicio (independiente). Si alguien ha encontrado una solución decente para ello, sería muy bienvenido
Miguel Guardo

1
Establecer los valores de acción táctil para la manipulación se acerca más al rendimiento deseado, pero como @MiguelGuardo dijo anteriormente, el efecto se pierde una vez que agrega la página web a su pantalla de inicio en iOS como una aplicación independiente.
T. Steele

Puede ser que alguien pueda piratear UIWebView - stackoverflow.com/questions/55155560/...
Eazy

43

Este complemento -FastClick desarrollado por Financial Times hace perfectamente para usted!

Sin embargo, asegúrese de agregar event.stopPropagation();y / o event.preventDefault();directamente después de la función de clic, de lo contrario, podría ejecutarse dos veces como lo hizo para mí, es decir:

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

});

3
Esto no es perfecto si está usando jquery mobile (versión 1.3.2 de todos modos), rompe el cierre del widget del panel github.com/jquery/jquery-mobile/issues/6440
ryan0

ese event.stopPropagation () es exactamente la razón por la que vine a esta página en primer lugar. Funciona perfectamente, ¡gracias!
Lukas

@Jonathan fastclickhace su magia solo en dispositivos táctiles que tienen un problema de retraso (de lo contrario, se omite automáticamente ). Sin embargo, simplemente agregar stopPropagation& preventDefaultdespués de cada evento de clic puede tener un efecto secundario no deseado en todos los controladores de eventos en todos los navegadores.
usuario

17

Sé que esto es antiguo, pero ¿no puedes simplemente probar para ver si el navegador es compatible con "touch"? Luego, ¿crear una variable que sea "tocar" o "hacer clic" y usar esa variable como el evento que se vincula a su elemento?

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

Entonces, esa muestra de código verifica si el evento "tocar" es compatible con el navegador y, si no, usamos el evento "clic".

(Editar: cambió "tocar" a "al tocar")


Gracias, me gusta la sencillez de esto. Me encantaría que otros repiquen sus posibles trampas.
tim peterson

4
El evento touchend no puede reemplazar el evento de clic debido a lo que @Andreas Köberle explica en su respuesta. Como, por ejemplo, si se desplaza y su dedo se detiene en un botón, activará el enlace ...
adriendenat

Esta es una solución increíblemente liviana sin tener que incluir una gran biblioteca adicional de cosas solo para deshacerse del retraso. ¡Ojalá pudiera votar 5 veces sobre este! (¡siempre y cuando no esté preocupado por el escenario de desplazamiento!)
tonejac

2
Para computadoras / navegadores con soporte de eventos de toque y clic, esta es una mala solución.
Alexander O'Mara

1
Algunos dispositivos admiten eventos táctiles y de clic, y desea que ambos se activen en diferentes situaciones. Hemos experimentado situaciones en las que algunas tabletas con Windows o Android que tienen un mouse obviamente dispararán un evento de clic cuando haga clic en una cosa, pero también dispararán eventos táctiles cuando toque. Esto significaba que tenías que escuchar ambos eventos. Como factor de complicación adicional, algunos dispositivos sintetizarían un evento de clic al tocar, por lo que escuchar ambos en esos dispositivos podría provocar que su controlador de eventos se disparara dos veces, a menos que tuviera cuidado.
1800 INFORMACIÓN

12

Me encontré con una alternativa muy popular llamada Hammer.js (página de Github) que creo que es el mejor enfoque.

Hammer.js es una biblioteca táctil con más funciones (tiene muchos comandos de deslizamiento) que Fastclick.js (la respuesta más votada).

Sin embargo, tenga cuidado: el desplazamiento rápido en dispositivos móviles tiende a bloquear realmente la interfaz de usuario cuando usa Hammer.js o Fastclick.js. Este es un problema importante si su sitio tiene un suministro de noticias o una interfaz donde los usuarios se desplazarán mucho (parecería que la mayoría de las aplicaciones web). Por esta razón, no estoy usando ninguno de estos complementos en este momento.


2
No use Hammerjs. Tiene algunos problemas graves, por ejemplo: github.com/EightMedia/hammer.js/issues/388 github.com/EightMedia/hammer.js/issues/366 Al menos no lo use hasta que se solucionen
Adonis K. Kakoulidis

2

De alguna manera, deshabilitar el zoom parece deshabilitar este pequeño retraso. Tiene sentido, ya que ya no es necesario tocar dos veces.

¿Cómo puedo "deshabilitar" el zoom en una página web móvil?

Pero tenga en cuenta el impacto en la usabilidad que esto tendrá. Puede ser útil para páginas web diseñadas como aplicaciones, pero no debería usarse para páginas 'estáticas' de propósito más general en mi humilde opinión. Lo uso para un proyecto de mascotas que necesita baja latencia.


1

Desafortunadamente, no existe una manera fácil de hacer esto. Entonces, usar touchstarto touchendte dejará con otros problemas, como que alguien comienza a desplazarse al hacer clic en un botón, por ejemplo. Usamos zepto por un tiempo, e incluso con este marco realmente bueno, hubo algunos problemas que surgieron con el tiempo. Muchos de ellos están cerrados , pero parece que no es un campo de solución simple.

Tenemos esta solución para manejar globalmente los clics en enlaces:

   $(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, gracias. ¿Abogaría por no utilizar la tapsolución general que publiqué y factorizar los tapeventos elemento por elemento?
tim peterson

No, ese no es el punto. El punto no es intentar construir una tapsolución por ti mismo. Actualizaré mi respuesta.
Andreas Köberle

- @ Andreas, gracias por tu respuesta, muchos eventos de clic son AJAX, por lo que el evento predeterminado ya está prevenido. ¿Le importaría actualizar su respuesta para manejar esto también? ¿Parecería que mi tapsolución general se vería igual que la suya en este caso?
tim peterson

1

Busqué una manera fácil sin jquery y sin biblioteca fastclick. Esto funciona para mi:

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 para proporcionar información adicional.

En iOS 10, <button> los electrónico de mi página no se podían activar continuamente. Siempre hubo un retraso.

Intenté fastclick / Hammer / tapjs / reemplazando el clic con touchstart, todo falló.

ACTUALIZACIÓN: ¡la razón parece ser que el botón está demasiado cerca del borde! ¡muévalo cerca del centro y el retraso desaparecerá!


0

Se supone que debes declarar explícitamente el modo pasivo :

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

    alert('fast touch');

}, { passive : true});

0

En jQuery puede vincular el evento "touch", que dispara el código inmediatamente después del toque (es como una tecla pulsada en el teclado). Probado en las versiones actuales de tabletas Chrome y Firefox. No olvide "hacer clic" también, para sus computadoras portátiles y dispositivos de escritorio con pantalla táctil.

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

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

	// everything else
});

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.