Di nuovo insieme per la prima volta
Introduzione
Per quasi trent'anni, le esperienze di computing desktop si sono basate su una tastiera e un mouse o un trackpad come principali dispositivi di input dell'utente. Tuttavia, nell'ultimo decennio, smartphone e tablet hanno introdotto un nuovo paradigma di interazione: il tocco. Con l'introduzione dei computer Windows 8 touch-screen e ora con il rilascio del fantastico Chromebook Pixel touch-screen, il tocco sta diventando parte dell'esperienza desktop prevista. Una delle sfide più grandi è creare esperienze che funzionino non solo sui dispositivi touch e con mouse, ma anche su questi dispositivi in cui l'utente utilizzerà entrambi i metodi di immissione, a volte contemporaneamente.
Questo articolo ti aiuterà a capire come le funzionalità touch sono integrate nel browser, come puoi integrare questo nuovo meccanismo di interfaccia nelle tue app esistenti e come il touch può interagire bene con l'input del mouse.
Lo stato del tocco nella piattaforma web
L'iPhone è stata la prima piattaforma popolare ad avere API touch dedicate integrate nel browser web. Diversi altri fornitori di browser hanno creato interfacce API simili, progettate per essere compatibili con l'implementazione di iOS, che ora è descritta dalla specifica "Touch Events version 1". Gli eventi touch sono supportati da Chrome e Firefox su computer, da Safari su iOS, da Chrome e dal browser Android su Android, nonché da altri browser mobile come il browser Blackberry.
Il mio collega Boris Smus ha scritto un ottimo tutorial di HTML5Rocks sugli eventi touch che è ancora un buon modo per iniziare se non hai mai esaminato gli eventi touch. Se non hai mai lavorato con gli eventi touch, leggi l'articolo prima di continuare. Vai avanti, io aspetto.
Hai finito? Ora che hai una conoscenza di base degli eventi touch, la sfida con la scrittura di interazioni abilitate al tocco è che le interazioni touch possono essere molto diverse dagli eventi del mouse (e del trackpad e della trackball che emulano il mouse) e, sebbene le interfacce touch in genere cerchino di emulare i mouse, questa emulazione non è perfetta o completa; devi davvero lavorare con entrambi gli stili di interazione e potresti dover supportare ogni interfaccia in modo indipendente.
Ancora più importante: l'utente potrebbe avere un touchscreen e un mouse
Molti sviluppatori hanno creato siti che rilevano staticamente se un ambiente supporta gli eventi touch e poi presumono di dover supportare solo gli eventi touch (e non quelli del mouse). Questa è ora un'ipotesi errata: la presenza di eventi touch non significa che l'utente utilizzi principalmente quel dispositivo di input tocco. Dispositivi come Chromebook Pixel e alcuni laptop Windows 8 ora supportano ENTRAMBI i metodi di input, mouse e input tocco, e altri lo faranno nel prossimo futuro. Su questi dispositivi, è abbastanza naturale per gli utenti utilizzare sia il mouse sia il touch screen per interagire con le applicazioni, quindi "supporta il tocco" non equivale a "non richiede il supporto del mouse". Non puoi pensare al problema come "Devo scrivere due stili di interazione diversi e passare da uno all'altro", devi pensare a come entrambe le interazioni funzioneranno insieme e in modo indipendente. Sul mio Chromebook Pixel, uso spesso il trackpad, ma tocco anche lo schermo: sulla stessa applicazione o pagina, faccio ciò che mi sembra più naturale al momento. D'altra parte, alcuni utenti di laptop touchscreen utilizzano raramente o mai il touchscreen, quindi la presenza dell'input tocco non dovrebbe disattivare o ostacolare il controllo del mouse.
Purtroppo, può essere difficile sapere se l'ambiente del browser di un utente supporta o meno l'input tocco. Idealmente, un browser su un computer desktop dovrebbe sempre indicare il supporto degli eventi touch, in modo che un display touchscreen possa essere collegato in qualsiasi momento (ad esempio, se diventa disponibile un touchscreen collegato tramite un KVM). Per tutti questi motivi, le tue applicazioni non dovrebbero tentare di passare dal tocco al mouse, ma semplicemente supportare entrambi.
Supporto di mouse e tocco insieme
#1 - Clic e tocchi: l'ordine "naturale" delle cose
Il primo problema è che le interfacce touch in genere cercano di emulare i clic del mouse, ovviamente, poiché le interfacce touch devono funzionare su applicazioni che in precedenza hanno interagito solo con gli eventi del mouse. Puoi utilizzarlo come scorciatoia, perché gli eventi "click" continueranno a essere attivati, indipendentemente dal fatto che l'utente abbia fatto clic con il mouse o abbia toccato lo schermo con il dito. Tuttavia, questa scorciatoia presenta un paio di problemi.
Innanzitutto, devi prestare attenzione quando progetti interazioni touch più avanzate: quando l'utente utilizza un mouse, risponderà tramite un evento di clic, ma quando l'utente tocca lo schermo, si verificheranno sia eventi di tocco che di clic. Per un singolo clic, l'ordine degli eventi è:
- touchstart
- touchmove
- touchend
- mouseover
- mousemove
- mousedown
- mouseup
- clic
Ciò significa, ovviamente, che se stai elaborando eventi touch come touchstart, devi assicurarti di non elaborare anche l'evento mousedown e/o l'evento di clic corrispondente. Se puoi annullare gli eventi touch (chiama preventDefault() all'interno del gestore di eventi), non verranno generati eventi del mouse per il tocco. Una delle regole più importanti dei gestori di eventi touch è:
Tuttavia, questo impedisce anche altri comportamenti predefiniti del browser (come lo scorrimento), anche se di solito l'evento touch viene gestito interamente nel gestore e vorrai disattivare le azioni predefinite. In generale, è consigliabile gestire e annullare tutti gli eventi touch o evitare di avere un gestore per quell'evento.
In secondo luogo, quando un utente tocca un elemento in una pagina web su un dispositivo mobile, le pagine che non sono state progettate per l'interazione mobile hanno un ritardo di almeno 300 millisecondi tra l'evento touchstart e l'elaborazione degli eventi del mouse (mousedown). Puoi farlo utilizzando Chrome: attiva "Emula eventi touch" negli Strumenti per sviluppatori di Chrome per testare le interfacce touch su un sistema non touch.
Questo ritardo serve a dare al browser il tempo di determinare se l'utente sta eseguendo un altro gesto, in particolare lo zoom con doppio tocco. Ovviamente, questo può essere problematico nei casi in cui vuoi avere una risposta istantanea al tocco di un dito. È in corso un lavoro per cercare di limitare gli scenari in cui questo ritardo si verifica automaticamente.
Il primo e più semplice modo per evitare questo ritardo è "comunicare" al browser mobile che la pagina non avrà bisogno dello zoom, il che può essere fatto utilizzando un viewport fisso, ad esempio inserendo nella pagina:
<meta name="viewport" content="width=device-width,user-scalable=no">
Questo non è sempre appropriato, ovviamente: disattiva lo zoom con pizzico, che potrebbe essere necessario per motivi di accessibilità, quindi usalo con parsimonia, se non del tutto (se disattivi la scalabilità dell'utente, potresti voler fornire un altro modo per aumentare la leggibilità del testo nella tua applicazione). Inoltre, per Chrome su dispositivi di tipo desktop che supportano il tocco e altri browser su piattaforme mobile quando la pagina ha aree visibili non scalabili, questo ritardo non viene applicato.
#2: gli eventi mousemove non vengono attivati dal tocco
A questo punto è importante notare che l'emulazione degli eventi del mouse in un'interfaccia touch in genere non si estende all'emulazione degli eventi mousemove. Pertanto, se crei un bel controllo basato sul mouse che utilizza gli eventi mousemove, probabilmente non funzionerà con un dispositivo touch, a meno che non aggiungi specificamente anche i gestori touchmove.
In genere, i browser implementano automaticamente l'interazione appropriata per le interazioni touch sui controlli HTML. Ad esempio, i controlli Range di HTML5 funzionano semplicemente quando utilizzi le interazioni touch. Tuttavia, se hai implementato i tuoi controlli, è probabile che non funzionino con le interazioni di tipo clicca e trascina; infatti, alcune librerie di uso comune (come jQueryUI) non supportano ancora in modo nativo le interazioni touch in questo modo (anche se per jQueryUI esistono diverse correzioni di monkey patching per questo problema). Questo è stato uno dei primi problemi che ho riscontrato durante l'upgrade della mia applicazione Web Audio Playground per l'utilizzo con il tocco: i cursori erano basati su jQueryUI, quindi non funzionavano con le interazioni di clic e trascinamento. Sono passato ai controlli intervallo HTML5 e hanno funzionato. In alternativa, ovviamente, avrei potuto semplicemente aggiungere gestori touchmove per aggiornare i cursori, ma c'è un problema…
#3: Touchmove e MouseMove non sono la stessa cosa
Un errore che ho visto commettere da alcuni sviluppatori è quello di far sì che i gestori touchmove e mousemove richiamino gli stessi percorsi di codice. Il comportamento di questi eventi è molto simile, ma leggermente diverso. In particolare, gli eventi touch hanno sempre come target l'elemento in cui è INIZIATO il tocco, mentre gli eventi del mouse hanno come target l'elemento attualmente sotto il cursore del mouse. Ecco perché abbiamo gli eventi mouseover e mouseout, ma non esistono eventi touchover e touchout corrispondenti, solo touchend.
Il modo più comune in cui questo può causare problemi è se rimuovi (o sposti) l'elemento che l'utente ha iniziato a toccare. Ad esempio, immagina un carosello di immagini con un gestore di tocco sull'intero carosello per supportare un comportamento di scorrimento personalizzato. Man mano che le immagini disponibili cambiano, rimuovi alcuni elementi <img> e ne aggiungi altri. Se l'utente inizia a toccare una di queste immagini e poi la rimuovi, il tuo gestore (che si trova su un predecessore dell'elemento img) smetterà di ricevere eventi touch (perché vengono inviati a un target che non è più nell'albero). Sembrerà che l'utente tenga il dito in un punto anche se potrebbe averlo spostato e infine rimosso.
Naturalmente, puoi evitare questo problema evitando di rimuovere gli elementi che hanno (o hanno predecessori che hanno) gestori di tocco mentre un tocco è attivo. In alternativa, la soluzione migliore è non registrare gestori touchend/touchmove statici, ma attendere di ricevere un evento touchstart e poi aggiungere gestori touchmove/touchend/touchcancel al target dell'evento touchstart (e rimuoverli alla fine/all'annullamento). In questo modo, continuerai a ricevere eventi per il tocco anche se l'elemento di destinazione viene spostato o rimosso. Puoi fare qualche prova qui: tocca la casella rossa e, tenendola premuta, premi Esc per rimuoverla dal DOM.
#4: Touch and :hover
La metafora del puntatore del mouse separava la posizione del cursore dalla selezione attiva, consentendo agli sviluppatori di utilizzare gli stati di passaggio del mouse per nascondere e mostrare informazioni che potrebbero essere pertinenti per gli utenti. Tuttavia, la maggior parte delle interfacce touch al momento non rileva un dito che "passa" sopra un target, quindi fornire informazioni semanticamente importanti (ad esempio, fornire un popup "Che cos'è questo controllo?") in base al passaggio del mouse è un no, a meno che non fornisci anche un modo touch-friendly per accedere a queste informazioni. Devi prestare attenzione a come utilizzi il passaggio del mouse per trasmettere informazioni agli utenti.
Tuttavia, è interessante notare che la pseudoclasse CSS :hover PUÒ essere attivata dalle interfacce touch in alcuni casi: toccando un elemento, questo diventa :active mentre il dito è premuto e acquisisce anche lo stato :hover. Con Internet Explorer, :hover è attivo solo quando l'utente tiene premuto il dito, mentre altri browser mantengono attivo :hover fino al tocco o al movimento del mouse successivo. Questo è un buon approccio per far funzionare i menu popup sulle interfacce touch: un effetto collaterale dell'attivazione di un elemento è che viene applicato anche lo stato :hover. Ad esempio:
<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 viene toccato un altro elemento, l'elemento non è più attivo e lo stato di passaggio del mouse scompare, proprio come se l'utente stesse utilizzando un puntatore del mouse e lo avesse spostato fuori dall'elemento. Potresti voler inserire i contenuti in un elemento <a> per renderli anche un punto di tabulazione. In questo modo, l'utente può attivare/disattivare le informazioni aggiuntive con un passaggio del mouse o un clic, un tocco o una pressione di un tasto, senza bisogno di JavaScript. Quando ho iniziato a lavorare per rendere il mio Web Audio Playground compatibile con le interfacce touch, ho avuto una piacevole sorpresa: i miei menu popup funzionavano già bene con il touch, perché avevo utilizzato questo tipo di struttura.
Il metodo descritto sopra funziona bene sia per le interfacce basate sul puntatore del mouse sia per le interfacce touch. Questo è in contrasto con l'utilizzo degli attributi "title" al passaggio del mouse, che NON verranno visualizzati quando l'elemento viene attivato:
<img src="/awesome.png" title="this doesn't show up in touch">
#5: Precisione del tocco rispetto al mouse
Sebbene i mouse abbiano una dissociazione concettuale dalla realtà, si rivelano estremamente precisi, poiché il sistema operativo sottostante generalmente monitora la precisione esatta dei pixel per il cursore. Gli sviluppatori di app mobile, invece, hanno imparato che i tocchi con le dita su un touch screen non sono così precisi, soprattutto a causa delle dimensioni della superficie del dito quando è a contatto con lo schermo (e in parte perché le dita ostruiscono lo schermo).
Molti privati e aziende hanno condotto ricerche approfondite con gli utenti su come progettare applicazioni e siti che supportino l'interazione basata sulle dita e sono stati scritti molti libri sull'argomento. Il consiglio di base è aumentare le dimensioni dei target di tocco aumentando il padding e ridurre la probabilità di tocchi errati aumentando il margine tra gli elementi. I margini non sono inclusi nella gestione del rilevamento dei risultati degli eventi di tocco e clic, mentre il padding sì. Una delle principali correzioni che ho dovuto apportare a Web Audio Playground è stata l'aumento delle dimensioni dei punti di connessione, in modo che fossero più facili da toccare con precisione.
Molti fornitori di browser che gestiscono interfacce basate sul tocco hanno anche introdotto una logica nel browser per aiutare a scegliere come target l'elemento corretto quando un utente tocca lo schermo e ridurre la probabilità di clic errati, anche se di solito questo corregge solo gli eventi di clic, non i movimenti (anche se Internet Explorer sembra modificare anche gli eventi mousedown/mousemove/mouseup).
#6: Keep touch handlers contained, or they’ll jank your scroll
È anche importante limitare i gestori di eventi touch solo agli elementi in cui sono necessari; gli elementi touch possono avere una larghezza di banda molto elevata, quindi è importante evitare i gestori di eventi touch sugli elementi di scorrimento (poiché l'elaborazione potrebbe interferire con le ottimizzazioni del browser per uno scorrimento touch rapido e senza interruzioni: i browser moderni provano a scorrere su un thread GPU, ma questo è impossibile se devono prima verificare con JavaScript se ogni evento touch verrà gestito dall'app). Puoi dare un'occhiata a un esempio di questo comportamento.
Un consiglio da seguire per evitare questo problema è assicurarti che, se gestisci gli eventi touch solo in una piccola parte della UI, colleghi i gestori touch solo lì (non, ad esempio, sul <body> della pagina); in breve, limita il più possibile l'ambito dei gestori touch.
#7: Multi-touch
L'ultima sfida interessante è che, sebbene l'abbiamo definita interfaccia utente "touch", quasi universalmente il supporto è in realtà per il multi-touch, ovvero le API forniscono più di un input tocco alla volta. Quando inizi a supportare il tocco nelle tue applicazioni, devi considerare in che modo i tocchi multipli potrebbero influire sulla tua applicazione.
Se hai creato app principalmente basate sul mouse, probabilmente hai utilizzato al massimo un punto del cursore, poiché i sistemi in genere non supportano più cursori del mouse. Per molte applicazioni, mapperai semplicemente gli eventi touch a un'unica interfaccia del cursore, ma la maggior parte dell'hardware che abbiamo visto per l'input tocco desktop può gestire almeno 2 input simultanei e la maggior parte del nuovo hardware sembra supportare almeno 5 input simultanei. Per sviluppare una tastiera di pianoforte sullo schermo, ovviamente, devi essere in grado di supportare più input tocco simultanei.
Le API Touch del W3C attualmente implementate non dispongono di un'API per determinare quanti punti di contatto sono supportati dall'hardware, quindi dovrai fare una stima di quanti punti di contatto vorranno i tuoi utenti o, ovviamente, prestare attenzione a quanti punti di contatto vedi in pratica e adattarti. Ad esempio, in un'applicazione per pianoforte, se non vedi mai più di due punti di contatto, potresti voler aggiungere un'interfaccia utente per gli "accordi". L'API PointerEvents dispone di un'API per determinare le funzionalità del dispositivo.
Ritocco in corso…
Ci auguriamo che questo articolo ti abbia fornito alcune indicazioni sulle sfide comuni nell'implementazione delle interazioni touch insieme a quelle del mouse. Naturalmente, il consiglio più importante è che devi testare la tua app su dispositivi mobili, tablet e ambienti desktop con mouse e touch screen combinati. Se non disponi di hardware touch+mouse, utilizza l'opzione "Emula eventi touch" di Chrome per testare i diversi scenari.
Non solo è possibile, ma è anche relativamente facile, seguendo queste indicazioni, creare esperienze interattive basate sul coinvolgimento che funzionano bene con l'input tocco, l'input del mouse e persino entrambi gli stili di interazione contemporaneamente.