Modo táctil y mouse

Juntos de nuevo por primera vez

Introducción

Durante casi treinta años, las experiencias de computación de escritorio se han centrado en el teclado y el mouse o el panel táctil como nuestros principales dispositivos de entrada del usuario. Sin embargo, durante la última década, los smartphones y las tablets trajeron un nuevo paradigma de interacción: el tacto. Con la introducción de las máquinas con Windows 8 táctiles y, ahora, con el lanzamiento de la increíble Chromebook Pixel táctil, la tecnología táctil se está convirtiendo en parte de la experiencia de escritorio esperada. Uno de los mayores desafíos es crear experiencias que funcionen no solo en dispositivos táctiles y con mouse, sino también en aquellos en los que el usuario use ambos métodos de entrada, a veces de forma simultánea.

Este artículo te ayudará a comprender cómo se integran las funciones táctiles en el navegador, cómo puedes integrar este nuevo mecanismo de interfaz en tus apps existentes y cómo las funciones táctiles pueden funcionar bien con la entrada del mouse.

El estado de la interacción táctil en la plataforma web

El iPhone fue la primera plataforma popular que tuvo APIs táctiles dedicadas integradas en el navegador web. Varios otros proveedores de navegadores crearon interfaces de API similares diseñadas para ser compatibles con la implementación de iOS, que ahora se describe en la especificación "Eventos táctiles versión 1". Los eventos táctiles son compatibles con Chrome y Firefox en computadoras de escritorio, con Safari en iOS, con Chrome y el navegador de Android en Android, y con otros navegadores para dispositivos móviles, como el de Blackberry.

Mi colega Boris Smus escribió un excelente instructivo de HTML5Rocks sobre eventos táctiles que sigue siendo una buena manera de comenzar si aún no los conoces. De hecho, si no trabajaste con eventos táctiles antes, lee ese artículo ahora, antes de continuar. Adelante, esperaré.

¿Terminaste? Ahora que tienes una base de conocimientos sobre los eventos táctiles, el desafío de escribir interacciones táctiles es que estas pueden ser bastante diferentes de los eventos del mouse (y del panel táctil y la bola de seguimiento que emulan el mouse). Aunque las interfaces táctiles suelen intentar emular los mouses, esa emulación no es perfecta ni completa. Realmente necesitas trabajar con ambos estilos de interacción y es posible que debas admitir cada interfaz de forma independiente.

Lo más importante: El usuario puede tener una pantalla táctil y un mouse

Muchos desarrolladores crearon sitios que detectan de forma estática si un entorno admite eventos táctiles y, luego, suponen que solo necesitan admitir eventos táctiles (y no de mouse). Esta es una suposición incorrecta. En cambio, el hecho de que haya eventos táctiles no significa que el usuario esté usando principalmente ese dispositivo de entrada táctil. Los dispositivos como la Chromebook Pixel y algunas laptops con Windows 8 ahora admiten métodos de entrada táctil y con mouse, y más dispositivos lo harán en el futuro cercano. En estos dispositivos, es bastante natural que los usuarios usen tanto el mouse como la pantalla táctil para interactuar con las aplicaciones, por lo que "admite la función táctil" no es lo mismo que "no necesita compatibilidad con el mouse". No puedes pensar en el problema como "Tengo que escribir dos estilos de interacción diferentes y alternar entre ellos", sino que debes pensar en cómo funcionarán ambas interacciones juntas y de forma independiente. En mi Chromebook Pixel, uso con frecuencia el panel táctil, pero también extiendo la mano y toco la pantalla. En la misma aplicación o página, hago lo que me parece más natural en el momento. Por otro lado, algunos usuarios de laptops con pantalla táctil rara vez la usarán, por lo que la presencia de la entrada táctil no debería inhabilitar ni obstaculizar el control del mouse.

Lamentablemente, puede ser difícil saber si el entorno del navegador de un usuario admite la entrada táctil o no. Lo ideal sería que un navegador en una máquina de escritorio siempre indicara la compatibilidad con los eventos táctiles para que se pudiera conectar una pantalla táctil en cualquier momento (p. ej., si una pantalla táctil conectada a través de un KVM estuviera disponible). Por todos estos motivos, tus aplicaciones no deberían intentar alternar entre la entrada táctil y el mouse, sino que deberían admitir ambas.

Compatibilidad con mouse y entrada táctil en conjunto

#1: Hacer clic y presionar: El orden "natural" de las cosas

El primer problema es que las interfaces táctiles suelen intentar emular los clics del mouse, lo que es obvio, ya que las interfaces táctiles deben funcionar en aplicaciones que antes solo interactuaban con eventos del mouse. Puedes usar esto como un atajo, ya que los eventos "click" se seguirán activando, independientemente de si el usuario hizo clic con el mouse o presionó la pantalla con el dedo. Sin embargo, este atajo tiene un par de problemas.

Primero, debes tener cuidado cuando diseñes interacciones táctiles más avanzadas: cuando el usuario use un mouse, responderá a través de un evento de clic, pero cuando el usuario toque la pantalla, se producirán eventos de toque y de clic. Para un solo clic, el orden de los eventos es el siguiente:

  1. touchstart
  2. touchmove
  3. touchend
  4. desplazar el mouse sobre un anuncios
  5. mousemove
  6. mousedown
  7. mouseup
  8. clic

Esto, por supuesto, significa que, si procesas eventos táctiles como touchstart, debes asegurarte de no procesar también los eventos mousedown o evento de clic correspondientes. Si puedes cancelar los eventos táctiles (llama a preventDefault() dentro del controlador de eventos), no se generarán eventos de mouse para los toques. Una de las reglas más importantes de los controladores táctiles es la siguiente:

Sin embargo, esto también evita otros comportamientos predeterminados del navegador (como el desplazamiento), aunque, por lo general, controlas el evento táctil por completo en tu controlador y QUERRÁS inhabilitar las acciones predeterminadas. En general, te recomendamos que controles y canceles todos los eventos táctiles, o bien que evites tener un controlador para ese evento.

En segundo lugar, cuando un usuario presiona un elemento en una página web en un dispositivo móvil, las páginas que no se diseñaron para la interacción móvil tienen una demora de al menos 300 milisegundos entre el evento touchstart y el procesamiento de los eventos del mouse (mousedown). Puedes hacerlo con Chrome. Activa "Emular eventos táctiles" en las herramientas para desarrolladores de Chrome para probar las interfaces táctiles en un sistema no táctil.

Esta demora permite que el navegador determine si el usuario está realizando otro gesto, en particular, el zoom de doble presión. Obviamente, esto puede ser problemático en los casos en los que quieras tener una respuesta instantánea al toque de un dedo. Se está trabajando para intentar limitar las situaciones en las que se produce este retraso de forma automática.

Chrome para Android Navegador Android Opera Mobile para Android) Firefox para Android Safari iOS
Viewport no escalable Sin retraso 300 ms 300 ms Sin retraso 300 ms
Sin viewport 300 ms 300 ms 300 ms 300 ms 300 ms

La primera y más sencilla forma de evitar este retraso es "indicarle" al navegador para dispositivos móviles que tu página no necesitará zoom, lo que se puede hacer con un viewport fijo, p.ej., insertando lo siguiente en tu página:

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

Por supuesto, esto no siempre es apropiado, ya que inhabilita el gesto de pellizcar para hacer zoom, que puede ser necesario por motivos de accesibilidad, así que úsalo con moderación (si inhabilitas el ajuste de escala del usuario, es posible que quieras proporcionar alguna otra forma de aumentar la legibilidad del texto en tu aplicación). Además, para Chrome en dispositivos de escritorio que admiten la función táctil y otros navegadores en plataformas móviles cuando la página tiene viewports que no son escalables, esta demora no se aplica.

#2: Los eventos de movimiento del mouse no se activan con el tacto

En este punto, es importante tener en cuenta que la emulación de eventos de mouse en una interfaz táctil no suele extenderse a la emulación de eventos mousemove, por lo que, si creas un hermoso control controlado por mouse que use eventos mousemove, es probable que no funcione con un dispositivo táctil, a menos que también agregues controladores touchmove de forma específica.

Por lo general, los navegadores implementan automáticamente la interacción adecuada para las interacciones táctiles en los controles HTML. Por ejemplo, los controles de rango de HTML5 funcionarán cuando uses interacciones táctiles. Sin embargo, si implementaste tus propios controles, es probable que no funcionen en las interacciones de tipo hacer clic y arrastrar. De hecho, algunas bibliotecas de uso frecuente (como jQueryUI) aún no admiten de forma nativa las interacciones táctiles de esta manera (aunque para jQueryUI, hay varias correcciones de parches para este problema). Este fue uno de los primeros problemas que encontré cuando actualicé mi aplicación Web Audio Playground para que funcionara con la función táctil: los controles deslizantes se basaban en jQueryUI, por lo que no funcionaban con las interacciones de hacer clic y arrastrar. Cambié a los controles de rango de HTML5 y funcionaron. Como alternativa, por supuesto, podría haber agregado controladores de touchmove para actualizar los controles deslizantes, pero hay un problema con eso…

#3: Touchmove y MouseMove no son lo mismo

Un error que vi que cometen algunos desarrolladores es que los controladores de touchmove y mousemove llamen a las mismas rutas de código. El comportamiento de estos eventos es muy similar, pero con diferencias sutiles. En particular, los eventos táctiles siempre se dirigen al elemento en el que se INICIÓ el toque, mientras que los eventos del mouse se dirigen al elemento que se encuentra actualmente debajo del cursor del mouse. Por eso, tenemos eventos mouseover y mouseout, pero no hay eventos touchover y touchout correspondientes, solo touchend.

La forma más común en que esto puede afectarte es si quitas (o reubicas) el elemento que el usuario comenzó a tocar. Por ejemplo, imagina un carrusel de imágenes con un controlador táctil en todo el carrusel para admitir un comportamiento de desplazamiento personalizado. A medida que cambian las imágenes disponibles, quitas algunos elementos <img> y agregas otros. Si el usuario comienza a tocar una de esas imágenes y luego la quitas, tu controlador (que se encuentra en un elemento superior del elemento img) dejará de recibir eventos táctiles (porque se envían a un destino que ya no está en el árbol). Parecerá que el usuario mantiene el dedo en un lugar, aunque lo haya movido y, finalmente, lo haya quitado.

Por supuesto, puedes evitar este problema si no quitas los elementos que tienen (o tienen ancestros que tienen) controladores táctiles mientras un toque está activo. Como alternativa, la mejor orientación es que, en lugar de registrar controladores estáticos de touchend/touchmove, esperes hasta que recibas un evento touchstart y, luego, agregues controladores de touchmove/touchend/touchcancel al destino del evento touchstart (y los quites al finalizar o cancelar). De esta manera, seguirás recibiendo eventos para el toque, incluso si el elemento de destino se mueve o se quita. Puedes probar esto un poco aquí: toca el cuadro rojo y, mientras lo mantienes presionado, presiona Escape para quitarlo del DOM.

Nº 4: Toque y :hover

La metáfora del puntero del mouse separó la posición del cursor de la selección activa, lo que permitió a los desarrolladores usar estados de colocar el cursor sobre un elemento para ocultar y mostrar información que podría ser pertinente para los usuarios. Sin embargo, la mayoría de las interfaces táctiles actuales no detectan cuando un dedo "se desplaza" sobre un objetivo, por lo que no se debe proporcionar información semánticamente importante (p.ej., proporcionar una ventana emergente con la pregunta "¿Qué es este control?") basada en el desplazamiento, a menos que también proporciones una forma táctil de acceder a esta información. Debes tener cuidado con la forma en que usas el desplazamiento para transmitir información a los usuarios.

Sin embargo, es interesante que la pseudoclase :hover de CSS PUEDE activarse con interfaces táctiles en algunos casos: presionar un elemento lo hace :active mientras el dedo está presionado, y también adquiere el estado :hover. (Con Internet Explorer, :hover solo se aplica mientras el usuario mantiene el dedo presionado; otros navegadores mantienen :hover hasta que se vuelve a presionar o se mueve el mouse). Este es un buen enfoque para que los menús emergentes funcionen en interfaces táctiles. Un efecto secundario de activar un elemento es que también se aplica el estado :hover. Por ejemplo:

<style>
img ~ .content {
  display:none;
}

img:hover ~ .content {
  display:block;
}
</style>

<img src="/awesome.png">
<div class="content">This is an awesome picture of me</div>

Una vez que se presiona otro elemento, el elemento deja de estar activo y el estado de desplazamiento desaparece, como si el usuario estuviera usando un puntero del mouse y lo alejara del elemento. Es posible que quieras unir el contenido en un elemento <a> para que también sea una tabulación. De esa manera, el usuario puede activar o desactivar la información adicional con un clic o un desplazamiento del mouse, un toque o una pulsación de tecla, sin necesidad de JavaScript. Me sorprendió gratamente cuando comencé a trabajar para que mi Web Audio Playground funcionara bien con interfaces táctiles, ya que mis menús emergentes ya funcionaban bien con la función táctil, porque había usado este tipo de estructura.

El método anterior funciona bien para las interfaces basadas en el puntero del mouse, así como para las interfaces táctiles. Esto contrasta con el uso de atributos "title" al colocar el cursor sobre el elemento, que NO se mostrarán cuando se active el elemento:

<img src="/awesome.png" title="this doesn't show up in touch">

#5: Precisión táctil frente a la del mouse

Si bien los ratones tienen una disociación conceptual de la realidad, resulta que son extremadamente precisos, ya que el sistema operativo subyacente suele realizar un seguimiento de la precisión exacta de los píxeles para el cursor. Por otro lado, los desarrolladores de dispositivos móviles aprendieron que los toques con los dedos en una pantalla táctil no son tan precisos, principalmente debido al tamaño de la superficie del dedo cuando está en contacto con la pantalla (y, en parte, porque los dedos obstruyen la pantalla).

Muchas personas y empresas realizaron investigaciones exhaustivas sobre los usuarios para diseñar aplicaciones y sitios que se adapten a la interacción con los dedos, y se escribieron muchos libros sobre el tema. El consejo básico es aumentar el tamaño de los objetivos táctiles incrementando el padding y reducir la probabilidad de presiones incorrectas aumentando el margen entre los elementos. (Los márgenes no se incluyen en el control de detección de hits de los eventos táctiles y de clic, mientras que el padding sí). Una de las principales correcciones que tuve que hacer en Web Audio Playground fue aumentar el tamaño de los puntos de conexión para que se pudieran tocar con mayor precisión.

Muchos proveedores de navegadores que manejan interfaces táctiles también introdujeron lógica en el navegador para ayudar a orientar el elemento correcto cuando un usuario toca la pantalla y reducir la probabilidad de clics incorrectos, aunque esto suele corregir solo los eventos de clic, no los movimientos (aunque Internet Explorer parece modificar también los eventos mousedown/mousemove/mouseup).

#6: Mantén los controladores táctiles contenidos o harán que el desplazamiento sea lento

También es importante mantener los controladores táctiles limitados solo a los elementos en los que los necesitas; los elementos táctiles pueden tener un ancho de banda muy alto, por lo que es importante evitar los controladores táctiles en los elementos de desplazamiento (ya que tu procesamiento puede interferir con las optimizaciones del navegador para un desplazamiento táctil rápido y sin tirones; los navegadores modernos intentan desplazarse en un subproceso de GPU, pero esto es imposible si primero tienen que verificar con JavaScript para ver si la app controlará cada evento táctil). Puedes consultar un ejemplo de este comportamiento.

Una recomendación para evitar este problema es asegurarte de que, si solo controlas eventos táctiles en una pequeña parte de tu IU, solo adjuntes controladores táctiles allí (no, por ejemplo, en el <body> de la página). En resumen, limita el alcance de tus controladores táctiles tanto como sea posible.

#7: Múltiples puntos de contacto

El último desafío interesante es que, aunque nos referimos a ella como interfaz de usuario "táctil", casi de forma universal, la compatibilidad es en realidad para la función multitáctil, es decir, las APIs proporcionan más de una entrada táctil a la vez. A medida que comiences a admitir la función táctil en tus aplicaciones, deberías considerar cómo podrían afectarlas los toques múltiples.

Si estuviste creando apps que se controlan principalmente con el mouse, es probable que estés acostumbrado a crear con un solo punto de cursor, ya que los sistemas no suelen admitir varios cursores de mouse. En muchas aplicaciones, solo asignarás eventos táctiles a una interfaz de cursor único, pero la mayoría del hardware que vimos para la entrada táctil de escritorio puede controlar al menos 2 entradas simultáneas, y la mayoría del hardware nuevo parece admitir al menos 5 entradas simultáneas. Por supuesto, para desarrollar un teclado de piano en pantalla, querrás admitir varias entradas táctiles simultáneas.

Las APIs de Touch de W3C implementadas actualmente no tienen una API para determinar cuántos puntos de contacto admite el hardware, por lo que tendrás que usar tu mejor estimación de cuántos puntos de contacto querrán tus usuarios o, por supuesto, prestar atención a cuántos puntos de contacto ves en la práctica y adaptarte. Por ejemplo, en una aplicación de piano, si nunca ves más de dos puntos de contacto, tal vez quieras agregar una IU de "acordes". La API de PointerEvents tiene una API para determinar las capacidades del dispositivo.

Retocando

Esperamos que este artículo te haya brindado orientación sobre los desafíos comunes que se presentan cuando se implementan interacciones táctiles junto con las del mouse. Por supuesto, lo más importante es que pruebes tu app en entornos de dispositivos móviles, tablets y computadoras de escritorio con mouse y pantalla táctil. Si no tienes hardware táctil y de mouse, usa la opción "Emular eventos táctiles" de Chrome para probar las diferentes situaciones.

No solo es posible, sino que también es relativamente fácil seguir estas pautas para crear experiencias interactivas atractivas que funcionen bien con la entrada táctil, la entrada del mouse y, incluso, ambos estilos de interacción al mismo tiempo.