Juntos de novo pela primeira vez
Introdução
Por quase 30 anos, as experiências de computação de mesa se concentravam em um teclado e um mouse ou trackpad como os principais dispositivos de entrada do usuário. No entanto, ao longo da última década, os smartphones e tablets trouxeram um novo paradigma de interação: o toque. Com a introdução de máquinas com tela touch do Windows 8 e agora com o lançamento do Chromebook Pixel com tela touch, a tela touch está se tornando parte da experiência esperada em computadores. Um dos maiores desafios é criar experiências que funcionem não apenas em dispositivos de toque e mouse, mas também nos dispositivos em que o usuário usará os dois métodos de entrada, às vezes simultaneamente.
Este artigo ajudará você a entender como os recursos de toque são integrados ao navegador, como integrar esse novo mecanismo de interface aos seus apps existentes e como o toque funciona bem com a entrada do mouse.
O estado do toque na plataforma da Web
O iPhone foi a primeira plataforma popular a ter APIs de toque dedicadas integradas ao navegador da Web. Vários outros fornecedores de navegadores criaram interfaces de API semelhantes, desenvolvidas para serem compatíveis com a implementação do iOS, que agora é descrita pela especificação "Eventos de toque versão 1". Os eventos de toque são compatíveis com o Chrome e o Firefox no computador, com o Safari no iOS e o Chrome e o navegador Android no Android, além de outros navegadores para dispositivos móveis, como o navegador Blackberry.
Meu colega Boris Smus escreveu um ótimo tutorial do HTML5Rocks sobre eventos de toque, que ainda é uma boa maneira de começar se você não conhece esse tipo de evento. Na verdade, se você nunca trabalhou com eventos de toque, leia esse artigo agora, antes de continuar. Pode continuar, vou esperar.
Terminou? Agora que você tem uma base básica em eventos de toque, o desafio de escrever interações com toque é que elas podem ser bastante diferentes dos eventos de mouse (e trackpad e trackball que emulam mouse). Embora as interfaces de toque geralmente tentem emular mouses, essa emulação não é perfeita ou completa. Você realmente precisa trabalhar com os dois estilos de interação e pode ter que oferecer suporte a cada interface de forma independente.
Mais importante: o usuário pode ter toque e mouse
Muitos desenvolvedores criaram sites que detectam de forma estática se um ambiente oferece suporte a eventos de toque e, em seguida, assumem que só precisam oferecer suporte a eventos de toque (e não de mouse). Essa é uma suposição incorreta. O fato de os eventos de toque estarem presentes não significa que o usuário está usando principalmente esse dispositivo de entrada por toque. Dispositivos como o Chromebook Pixel e alguns laptops com Windows 8 agora oferecem suporte a AMBOS métodos de entrada por mouse e toque, e mais dispositivos vão oferecer suporte a esses métodos em breve. Nesses dispositivos, é bastante natural que os usuários usem o mouse e a tela touch para interagir com os aplicativos. Portanto, "oferece suporte a toque" não é o mesmo que "não precisa de suporte a mouse". Não pense no problema como "preciso escrever dois estilos de interação diferentes e alternar entre eles". Pense em como as duas interações vão funcionar juntas e independentemente. No meu Chromebook Pixel, uso com frequência o trackpad, mas também estendo o braço e toco na tela. No mesmo aplicativo ou página, faço o que parece mais natural no momento. Por outro lado, alguns usuários de laptops com tela sensível ao toque raramente usam a tela sensível ao toque. Portanto, a presença de entrada por toque não deve desativar nem prejudicar o controle do mouse.
Infelizmente, pode ser difícil saber se o ambiente do navegador do usuário é compatível com entrada por toque. O ideal é que um navegador em um computador desktop sempre indique suporte a eventos de toque para que uma tela touchscreen possa ser conectada a qualquer momento (por exemplo, se uma tela touchscreen conectada por uma KVM for disponibilizada). Por todos esses motivos, seus aplicativos não devem tentar alternar entre toque e mouse. Ofereça suporte a ambos.
Suporte para mouse e toque
1. Clicar e tocar - a ordem "natural" das coisas
O primeiro problema é que as interfaces de toque normalmente tentam emular os cliques do mouse. Obviamente, elas precisam funcionar em aplicativos que só interagiram com eventos de mouse antes. Você pode usar isso como um atalho, porque os eventos de "clique" vão continuar sendo acionados, seja quando o usuário clicar com o mouse ou tocar na tela. No entanto, há alguns problemas com esse atalho.
Primeiro, você precisa ter cuidado ao projetar interações de toque mais avançadas: quando o usuário usa um mouse, ele responde por um evento de clique, mas quando o usuário toca na tela, os eventos de toque e clique ocorrem. Para um único clique, a ordem dos eventos é a seguinte:
- touchstart
- touchmove
- touchend
- mouseover
- mousemove
- mousedown
- mouseup
- clique
Isso significa, é claro, que, se você estiver processando eventos de toque, como touchstart, não processe o evento mousedown e/ou click correspondente. Se você puder cancelar os eventos de toque (chame preventDefault() dentro do manipulador de eventos), nenhum evento de mouse será gerado para toque. Uma das regras mais importantes dos processadores de toque é:
No entanto, isso também impede outros comportamentos padrão do navegador (como a rolagem), embora você geralmente processe o evento de toque totalmente no gerenciador e queira desativar as ações padrão. Em geral, você vai querer manipular e cancelar todos os eventos de toque ou evitar ter um manipulador para esse evento.
Em segundo lugar, quando um usuário toca em um elemento de uma página da Web em um dispositivo móvel, as páginas que não foram projetadas para interação móvel têm um atraso de pelo menos 300 milissegundos entre o evento touchstart e o processamento dos eventos do mouse (mousedown). Isso pode ser feito no Chrome. Basta ativar a opção Emular eventos de toque nas Ferramentas para desenvolvedores do Chrome para testar as interfaces de toque em um sistema sem toque.
Esse atraso permite que o navegador determine se o usuário está realizando outro gesto, em particular, o zoom duplo. Obviamente, isso pode ser problemático nos casos em que você quer ter uma resposta instantânea ao toque do dedo. Estamos trabalhando nisso para tentar limitar os cenários em que esse atraso ocorre automaticamente.
A primeira e mais fácil maneira de evitar esse atraso é "dizer" ao navegador para dispositivos móveis que a página não vai precisar de zoom. Isso pode ser feito usando uma janela de visualização fixa, por exemplo, inserindo na página:
<meta name="viewport" content="width=device-width,user-scalable=no">
Isso não é sempre apropriado, é claro. Isso desativa o zoom de pinça, que pode ser necessário por motivos de acessibilidade. Portanto, use-o com moderação (se você desativar a escala do usuário, talvez seja necessário fornecer outra maneira de aumentar a legibilidade do texto no aplicativo). Além disso, para o Chrome em dispositivos de classe desktop compatíveis com toque e outros navegadores em plataformas móveis quando a página tem janelas de visualização que não são escalonáveis, esse atraso não se aplica.
#2: Os eventos de movimento do mouse não são acionados por toque
É importante observar que a emulação de eventos do mouse em uma interface de toque normalmente não se estende à emulação de eventos mousemove. Portanto, se você criar um controle controlado por mouse que use eventos mousemove, ele provavelmente não funcionará com um dispositivo touchscreen, a menos que você adicione gerenciadores de touchmove especificamente.
Os navegadores geralmente implementam automaticamente a interação adequada para interações por toque nos controles HTML. Por exemplo, os controles de intervalo do HTML5 só funcionam quando você usa interações por toque. No entanto, se você implementou seus próprios controles, eles provavelmente não funcionarão em interações do tipo clicar e arrastar. Na verdade, algumas bibliotecas comumente usadas (como a jQueryUI) ainda não oferecem suporte nativo a interações de toque dessa forma (embora haja várias correções "mackey-patch" para esse problema no jQueryUI). Esse foi um dos primeiros problemas que encontrei ao atualizar meu aplicativo Web Audio Playground para funcionar com toque. Os controles deslizantes eram baseados no jQueryUI, então não funcionavam com interações de clique e arrasto. Mudei para os controles de intervalo HTML5, e eles funcionaram. Como alternativa, é claro, eu poderia simplesmente adicionar manipuladores de touchmove para atualizar os controles deslizantes, mas há um problema com isso…
#3: Touchmove e MouseMove não são a mesma coisa
Um problema que alguns desenvolvedores enfrentam é ter manipuladores de touchmove e mousemove que chamam os mesmos caminhos de código. O comportamento desses eventos é muito semelhante, mas sutilmente diferente. Em particular, os eventos de toque sempre são direcionados ao elemento em que o toque COMEÇOU, enquanto os eventos de mouse são direcionados ao elemento que está sob o cursor do mouse. É por isso que temos eventos mouseover e mouseout, mas não há eventos touchover e touchout correspondentes, apenas touchend.
A maneira mais comum de isso acontecer é se você remover (ou realocar) o elemento que o usuário começou a tocar. Por exemplo, imagine um carrossel de imagens com um gerenciador de toque em todo o carrossel para oferecer suporte ao comportamento de rolagem personalizado. À medida que as imagens disponíveis mudam, você remove alguns elementos <img>
e adiciona outros. Se o usuário começar a tocar em uma dessas imagens e você removê-la, seu manipulador (que está em um ancestral do elemento img) apenas deixará de receber eventos de toque (porque eles estão sendo enviados para um alvo que não está mais na árvore). É como se o usuário estivesse segurando seu dedo em um lugar mesmo que ele possa ter se movido e removido.
Para evitar esse problema, evite remover elementos que tenham (ou tenham ancestrais que tenham) gerenciadores de toque enquanto um toque estiver ativo. Como alternativa, a melhor orientação é, em vez de registrar manipuladores estáticos de touchend/touchmove, esperar até receber um evento touchstart e adicionar manipuladores touchmove/touchend/touchcancel ao destino do evento touchstart (e removê-los no final/cancelamento). Dessa forma, você vai continuar recebendo eventos de toque, mesmo que o elemento de destino seja movido/removido. Você pode brincar um pouco com isso aqui: toque na caixa vermelha e, enquanto pressiona a tecla Escape, remova-a do DOM.
#4: Toque e :Flutuar
A metáfora do ponteiro do mouse separou a posição do cursor da seleção ativa, e isso permitiu que os desenvolvedores usassem estados de passagem de cursor para ocultar e mostrar informações que poderiam ser pertinentes aos usuários. No entanto, a maioria das interfaces com tela touch não detecta um dedo "pairando" sobre um alvo. Portanto, não é possível fornecer informações semanticamente importantes (por exemplo, um pop-up "O que é esse controle?") com base no pairar, a menos que você também forneça uma maneira fácil de acessar essas informações. É preciso ter cuidado com a forma como você usa o cursor para transmitir informações aos usuários.
Curiosamente, a pseudoclasse CSS :hover PODE ser acionada por interfaces de toque em alguns casos. Tocar em um elemento faz com que ele fique :ativo enquanto o dedo está pressionado e também adquire o estado :hover. No Internet Explorer, o :hover só tem efeito enquanto o dedo do usuário está pressionado. Outros navegadores mantêm o :hover em efeito até o próximo toque ou movimento do mouse. Essa é uma boa abordagem para fazer com que os menus pop-out funcionem em interfaces com tela touch. Um efeito colateral de ativar um elemento é que o estado :hover também é aplicado. Exemplo:
<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>
Quando outro elemento é tocado, ele não fica mais ativo e o estado de passar o cursor desaparece, como se o usuário estivesse usando um ponteiro do mouse e o tivesse movido para fora do elemento. Talvez você queira incluir o conteúdo em um elemento <a>
para torná-lo um ponto de tabulação. Assim, o usuário pode alternar as informações extras com um movimento do mouse, um clique, um toque ou uma tecla, sem precisar de JavaScript. Fiquei agradavelmente surpreso quando comecei a trabalhar para que meu Web Audio Playground funcionasse bem com interfaces de toque, já que meus menus pop-up já funcionavam bem no toque, porque eu usei esse tipo de estrutura.
O método acima funciona bem para interfaces baseadas em ponteiro do mouse e para interfaces com toque. Isso contrasta com o uso de atributos "title" ao passar o cursor, que NÃO aparecem quando o elemento é ativado:
<img src="/awesome.png" title="this doesn't show up in touch">
#5: Precisão do toque x precisão do mouse
Embora os mouses tenham uma desagregação conceitual da realidade, eles são extremamente precisos, já que o sistema operacional subjacente geralmente rastreia a precisão exata do cursor em pixels. Por outro lado, os desenvolvedores de apps para dispositivos móveis aprenderam que os toques em uma tela touch não são tão precisos, principalmente devido ao tamanho da área de superfície do dedo em contato com a tela e, em parte, porque os dedos obstruem a tela.
Muitas pessoas e empresas fizeram pesquisas extensas com usuários sobre como projetar aplicativos e sites que acomodam a interação baseada em dedos, e muitos livros foram escritos sobre o assunto. O conselho básico é aumentar o tamanho das áreas de toque aumentando o padding e reduzir a probabilidade de toques incorretos aumentando a margem entre os elementos. As margens não estão incluídas no tratamento de detecção de hits dos eventos de toque e clique, enquanto o preenchimento está. Uma das principais correções que precisei fazer no Web Audio Playground foi aumentar o tamanho dos pontos de conexão para que eles pudessem ser tocados com mais facilidade.
Muitos fornecedores de navegadores que estão lidando com interfaces baseadas em toque também introduziram lógica no navegador para ajudar a segmentar o elemento correto quando um usuário toca na tela e reduzir a probabilidade de cliques incorretos, embora isso geralmente corrija apenas eventos de clique, não de movimento (embora o Internet Explorer pareça modificar eventos mousedown/mousemove/mouseup também).
6. Mantenha os gerenciadores de toque contidos para que não atrapalhem a rolagem
Também é importante manter os manipuladores de toque confinados apenas aos elementos em que você precisa deles. Os elementos de toque podem ter largura de banda muito alta, por isso é importante evitar manipuladores de toque em elementos de rolagem. Isso porque seu processamento pode interferir nos otimizações do navegador para rolagem rápida sem engasgos. Os navegadores modernos tentam rolar em uma linha de execução da GPU, mas isso é impossível se eles precisarem verificar primeiro com o JavaScript se cada evento de toque será processado pelo app. Confira um exemplo desse comportamento.
Uma orientação a ser seguida para evitar esse problema é garantir que, se você estiver processando apenas eventos de toque em uma pequena parte da interface, apenas anexe os manipuladores de toque nela (não, por exemplo, na <body>
da página). Em resumo, limite o escopo dos manipuladores de toque o máximo possível.
#7: Multitoque
O último desafio interessante é que, embora tenhamos nos referido a ele como interface do usuário "Touch", quase universalmente o suporte é para multitoque, ou seja, as APIs fornecem mais de uma entrada de toque por vez. Ao começar a oferecer suporte ao toque nos seus apps, considere como vários toques podem afetá-los.
Se você tem criado apps principalmente com base no mouse, está acostumado a criar com no máximo um ponto de cursor. Os sistemas geralmente não oferecem suporte a vários cursores de mouse. Para muitos aplicativos, você estará apenas mapeando eventos de toque para uma única interface de cursor, mas a maior parte do hardware que vimos para entrada por toque em computadores pode lidar com pelo menos duas entradas simultâneas, e a maioria dos novos hardwares parece oferecer suporte a pelo menos cinco entradas simultâneas. Para desenvolver um teclado de piano na tela, seria necessário oferecer suporte a várias entradas de toque simultâneas.
As APIs W3C Touch implementadas atualmente não têm uma API para determinar quantos pontos de contato o hardware oferece suporte. Portanto, você vai precisar usar sua melhor estimativa de quantos pontos de contato os usuários vão querer ou, é claro, prestar atenção em quantos pontos de contato você vê na prática e se adaptar. Por exemplo, em um aplicativo de piano, se você nunca encontrar mais de dois pontos de toque, talvez seja necessário adicionar uma interface de "acordes". A API PointerEvents tem uma API para determinar os recursos do dispositivo.
Retoques
Esperamos que este artigo tenha oferecido algumas orientações sobre desafios comuns na implementação de interações por toque e mouse. Mais importante do que qualquer outro conselho, é claro, é que você precisa testar o app em dispositivos móveis, tablets e ambientes de computador com mouse e toque. Se você não tiver hardware de toque e mouse, use a opção Emulate touch events (emular eventos de toque) do Chrome para testar os diferentes cenários.
É possível e relativamente fácil seguir essas orientações para criar experiências interativas envolventes que funcionem bem com entrada por toque, entrada por mouse e até mesmo com os dois estilos de interação ao mesmo tempo.