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 com tela touchscreen e mouse, mas também em dispositivos em que o usuário usa os dois métodos de entrada, às vezes simultaneamente.
Este artigo vai ajudar você a entender como os recursos de toque são integrados ao navegador, como integrar esse novo mecanismo de interface aos seus apps e como o toque pode funcionar 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 criadas para serem compatíveis com a implementação do iOS, que agora é descrita pela especificação"Touch Events version 1". Os eventos de toque têm suporte do Chrome e do Firefox no computador, do Safari no iOS e do Chrome e do 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ê nunca usou esse tipo de evento. Na verdade, se você nunca trabalhou com eventos de toque, leia esse artigo agora, antes de continuar. Pode falar, eu espero.
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.
O mais importante: o usuário pode ter toque e um 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 touchscreen 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 de um usuário oferece suporte à entrada por toque. O ideal é que um navegador em uma máquina desktop sempre indique suporte a eventos de toque para que uma tela touchscreen possa ser anexada a qualquer momento (por exemplo, se uma tela touchscreen conectada a um KVM estiver disponível). 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 cliques do mouse, obviamente, já que precisam funcionar em apps que só interagiram com eventos do mouse antes. Você pode usar isso como um atalho, porque os eventos de "clique" continuam sendo acionados, seja quando o usuário clica com o mouse ou toca na tela. No entanto, esse atalho tem alguns problemas.
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 seu gerenciador e queira desativar as ações padrão. Em geral, é necessário processar 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 em 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 de início do toque e o processamento de eventos do mouse (mousedown). Isso pode ser feito usando o Chrome. Ative a opção "Emulação de eventos de toque" nas Ferramentas para desenvolvedores do Chrome para testar 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 com dois toques. Obviamente, isso pode ser problemático nos casos em que você quer uma resposta instantânea ao toque de um 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 com suporte ao toque e outros navegadores em plataformas móveis, quando a página tem visualizações 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 para a emulação de eventos mousemove. Portanto, se você criar um controle controlado por mouse que usa eventos mousemove, ele provavelmente não vai funcionar com um dispositivo touchscreen, a menos que você adicione gerenciadores de touchmove.
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 vão funcionar em interações do tipo clique e arraste. Na verdade, algumas bibliotecas usadas com frequência (como o jQueryUI) ainda não oferecem suporte nativo a interações por toque dessa forma. No entanto, para o jQueryUI, há vários patches de correção para esse problema. 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 do HTML5, e eles funcionaram. 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 vi alguns desenvolvedores enfrentar é 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 segmentam o elemento em que o toque COMEÇOU, enquanto os eventos do mouse segmentam o elemento que está sob o cursor do mouse. É por isso que temos eventos de passagem do cursor e de saída do cursor, mas não há eventos de toque e de saída de toque correspondentes, apenas de toque final.
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ê a remover, o gerenciador (que está em um ancestral do elemento img) vai parar de receber eventos de toque porque eles estão sendo enviados para um destino que não está mais na árvore. Vai parecer que o usuário está segurando o dedo em um lugar, mesmo que ele tenha se movido e removido a imagem.
É possível evitar esse problema removendo elementos que têm (ou têm ancestrais que têm) processadores de toque enquanto um toque está 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 alvo 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 :Passar o cursor
A metáfora do ponteiro do mouse separa a posição do cursor da seleção ativa, permitindo que os desenvolvedores usem estados de passagem do cursor para ocultar e mostrar informações que podem ser pertinentes para os 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, o 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. Em outros navegadores, o :hover permanece em vigor até o próximo toque ou movimento do mouse. Essa é uma boa abordagem para fazer com que os menus pop-up funcionem em interfaces de toque. 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 clique ou um toque no mouse, um toque no touchscreen 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" no passar do 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 são incluídas no processamento de detecção de acerto de eventos de toque e clique, mas o padding é. 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 manipuladores de toque contidos ou eles vão causar problemas no seu 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 seguir 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 ela 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. Em muitos aplicativos, você vai apenas mapear eventos de toque para uma única interface de cursor, mas a maioria dos hardwares que vimos para entrada por toque em computadores pode processar pelo menos duas entradas simultâneas, e a maioria dos hardwares novos parece oferecer suporte a pelo menos cinco entradas simultâneas. Para desenvolver um teclado de piano na tela, é claro, você precisa 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. O conselho mais importante, é claro, é 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 Emulação de 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.