Reduciendo el lag de las aplicaciones HTML5 en móvil

El problema

Una de las principales críticas a los frameworks HTML5 utilizados para implementar aplicaciones móviles, ha sido siempre en general la falta de fluidez en la respuesta a eventos. Esto produce una experiencia menos satisfactoria si comparamos esta sensación con la que tenemos cuando trabajamos con una aplicación nativa.

El problema es que, a la hora de seleccionar elementos, arrastrar o ampliar zonas de la pantalla en dispositivos móviles, hay que tener en cuanta que, al carecer de un dispositivo de selección como un ratón y tratándose de una pantalla táctil, los eventos tradicionales que son básicos en navegadores de escritorio como son por ejemplo click, aquí no son suficientes.

La aparición de nuevos dispositivos con unos requisitos nuevos, han motivado que aparezcan nuevos tipos de eventos cuando realizamos una selección simple o doble sobre un elemento de nuestra pantalla táctil. A este nuevo conjunto de eventos, se las ha dado la denominación de touch events.

El problema en la gestión de este nuevo tipo de eventos en el navegador es que cuando realizamos acciones, el navegador de nuestro dispositivo móvil no lanza el evento de click hasta que no han pasado unos 300ms desde que se ha recibido el primer contacto con la pantalla.

Este retraso o lag introducido sirve al navegador para diferencia entre un click estándar y la primera mitad de un selección doble con el dedo en la pantalla táctil.

En consecuencia, este retraso introducido hace que la experiencia de usuario no sea la esperada en comparación con la que obtenemos en aplicaciones nativas.

Si quieres comprobar por ti mismo el efecto de estos eventos, en este ejemplo que puedes ejecutar online hemos definido un botón convencional que escucha dos eventos, el primero almacenará los milisegundos transcurridos desde que se realiza la acción hasta que el evento touch concluye (touchend) y el segundo calculará el tiempo transcurrido hasta que finalmente el evento de click es recibido.

ATENCIÓN: Ten en cuenta que este ejemplo, al definir eventos touch, sólo nos mostrará un resultado válido si accedemos desde un dispositivo móvil o si activamos en las Chrome Tools la emulación móvil.

Los distintos escenarios

Es curioso ver como, en función del navegador y del sistema operativo, este comportamiento puede ser distinto.

En Chrome y Firefox para Android, si el navegador detecta que nuestra página tiene definido el meta de viewport, entonces ya no introduce el retraso:

1
<meta name="viewport" content="width=device-width">

Es importante tener en cuenta que en Chrome versión +32 en Android este retraso ya está completamente desactivado.

Si hablamos de Internet Explorer en Windows Phone, la opción pasa por definido una propiedad CSS llamada touch-action:

1
2
3
button {
touch-action: manipulation;
}

Finalmente, aunque no había forma de evitar este delay en iOS, con la llegada de iOS 8 esto ha cambiado ligeramente y en Safari, el delay se ha eliminido en en los slow taps siguiendo aún activo para los fast taps (tiempo de duración de la acción de selección en móvil o simplemente el rato que tenemos el dedo encima de la pantalla estando el límite alrededor de los 125ms).

Si tenéis un iPhone, podéis probar el ejemplo de antes haciendo una pulsación lenta y una rápida y ver así la diferencia de lag o comprobar el efecto en este vídeo.

Soluciones

Como alternativa a este tipo de hacks para cada navegador y plataforma, una opción interesante es la inclusión en nuestros proyectos móviles de FastClick.

Esta librería desarrollada por el equipo del Financial Times, se encargará de detectar los eventos touch y de forzar un evento click cada vez que se llegue un touchend, evitando la acción del click real que se produciría 300ms después.

Para incluirla en nuestro proyecto, sólo tenemos que añadir el fichero JavaScript correspondiente a nuestro HTML:

1
<script src="/path/to/fastclick.js"></script>

Y posteriormente activar FastClick:

1
2
3
4
5
<script>
$(function() {
FastClick.attach(document.body);
});
</script>