Together again for the first time
Wprowadzenie
Od prawie 30 lat komputery osobiste korzystają z klawiatury i myszy lub trackpada jako głównych urządzeń do wprowadzania danych. W ostatniej dekadzie smartfony i tablety wprowadziły jednak nowy model interakcji: dotykowy. Wraz z pojawieniem się komputerów z systemem Windows 8 z obsługą dotyku, a teraz wraz z pojawieniem się niesamowitego Chromebooka Pixel z obsługą dotykową, dotyk staje się coraz bardziej popularny na komputerach. Jednym z największych wyzwań jest tworzenie funkcji, które działają nie tylko na urządzeniach dotykowych i myszach, ale także na urządzeniach, na których użytkownik używa obu metod wprowadzania – czasami jednocześnie.
Ten artykuł pomoże Ci zrozumieć, jak funkcje dotykowe są wbudowane w przeglądarkę, jak możesz zintegrować nowy mechanizm z istniejącymi aplikacjami oraz jak sprawnie obsługiwać dotyk przy użyciu myszy.
Stan dotyku na platformie internetowej
iPhone był pierwszą popularną platformą z wbudowanymi w przeglądarkę internetową interfejsami API dotykowych. Kilku innych dostawców przeglądarek stworzyło podobne interfejsy API, które są zgodne z implementacją na iOS, opisaną w specyfikacji „Touch Events w wersji 1”. Zdarzenia dotknięcia są obsługiwane przez przeglądarki Chrome i Firefox na komputerze oraz w przeglądarce Safari na urządzeniach z iOS i Chrome i w przeglądarce na Androida na Androidzie, a także w innych przeglądarkach mobilnych, takich jak BlackBerry.
Mój współpracownik Boris Smus napisał świetny samouczek HTML5Rocks na temat zdarzeń dotykowych, który jest świetnym wprowadzeniem do tej tematyki, jeśli nie zajmowałeś/zajmowałaś się wcześniej zdarzeniami dotykowymi. Jeśli nie masz jeszcze doświadczenia ze zdarzeniami dotknięcia, przeczytaj ten artykuł teraz, zanim przejdziesz dalej. Proszę, zaczekam.
Wszystko gotowe? Teraz, gdy masz już podstawową wiedzę na temat zdarzeń dotykowych, możesz się zmierzyć z wyzwaniem, jakim jest pisanie interakcji z użyciem ekranu dotykowego. Interakcje dotykowe mogą się znacznie różnić od zdarzeń myszy (i myszy emulujących trackpad i kulkę) – i chociaż interfejsy dotykowe zwykle próbują emulować mysz, ta emulacja nie jest idealna ani kompletna. Musisz więc pracować nad obydwoma stylami interakcji i być może musisz obsługiwać każdy interfejs osobno.
Najważniejsze: użytkownik może mieć do dyspozycji ekran dotykowy i mysz
Wielu programistów tworzy witryny, które statycznie wykrywają, czy środowisko obsługuje zdarzenia dotyku, i zakłada, że muszą obsługiwać zdarzenia dotyku (a nie myszy). Teraz jest to błędne założenie – obecność zdarzeń dotyku nie oznacza, że użytkownik korzysta głównie z takiego urządzenia. Urządzenia takie jak Chromebook Pixel i niektóre laptopy z systemem Windows 8 obsługują teraz obie metody wprowadzania danych: za pomocą myszy i dotyku. W najbliższej przyszłości dołączy do nich więcej urządzeń. Na tych urządzeniach użytkownicy naturalnie korzystają z myszy i ekranu dotykowego, aby wchodzić w interakcje z aplikacją, więc „obsługa ekranu dotykowego” nie jest tym samym, co „nie wymaga obsługi myszy”. Nie możesz myśleć o problemie w ten sposób: „Muszę napisać 2 różne style interakcji i przełączać się między nimi”. Musisz zastanowić się, jak obie interakcje będą działać razem i osobno. Na moim Chromebooku Pixel często używam trackpada, ale czasami też dotykam ekranu – w tej samej aplikacji lub na tej samej stronie robię to, co wydaje mi się najbardziej naturalne w danym momencie. Z drugiej strony, niektórzy użytkownicy laptopów z ekranem dotykowym rzadko korzystają z tego ekranu, więc obecność ekranu dotykowego nie powinna uniemożliwiać korzystania z myszy.
Niestety trudno jest określić, czy środowisko przeglądarki użytkownika obsługuje wprowadzanie za pomocą dotyku.W idealnej sytuacji przeglądarka na komputerze stacjonarnym zawsze powinna wskazywać obsługę zdarzeń dotykowych, aby można było w dowolnym momencie podłączyć ekran dotykowy (np. gdy stanie się dostępny ekran dotykowy podłączony przez przełącznik KVM). Z tych wszystkich powodów aplikacje nie powinny przełączać się między dotykiem a myszką – powinny obsługiwać obie te metody.
Obsługa myszy i dotyku
1. Klikanie i dotykanie – „naturalny” porządek rzeczy
Pierwszym problemem jest to, że interfejsy dotykowe zwykle próbują emulować kliknięcia myszką. Jest to oczywiste, ponieważ interfejsy dotykowe muszą działać w aplikacjach, które wcześniej obsługiwały tylko zdarzenia myszy. Możesz użyć tego jako skrótu, ponieważ zdarzenia „kliknięcia” będą nadal wywoływane, niezależnie od tego, czy użytkownik kliknął myszką, czy palcem na ekranie. Jednak z tym skrótem wiąże się kilka problemów.
Po pierwsze, musisz zachować ostrożność podczas projektowania bardziej zaawansowanych interakcji dotykowych: gdy użytkownik używa myszy, aplikacja reaguje na to zdarzeniem kliknięcia, ale gdy dotyka ekranu, występują zarówno zdarzenia dotyku, jak i kliknięcia. W przypadku pojedynczego kliknięcia kolejność zdarzeń jest następująca:
- touchstart
- touchmove
- touchend
- ruch kursora myszy|najechanie kursorem myszy (na obiekt)
- mousemove
- mousedown
- kursor na górze
- click
Oznacza to oczywiście, że jeśli przetwarzasz zdarzenia dotykowe, takie jak touchstart, musisz się upewnić, że nie przetwarzasz też odpowiadających im zdarzeń mousedown ani click. Jeśli możesz anulować zdarzenia dotykowe (wywołując metodę preventDefault() w obiekcie event handler), żadne zdarzenia myszy nie będą generowane w przypadku dotyku. Jedna z najważniejszych zasad dotyczących elementów sterujących dotykiem:
Jednak powoduje to również blokowanie innych domyślnych zachowań przeglądarki (np. przewijania). Zwykle jednak zdarzenie dotyku obsługujesz całkowicie w obsługującym go elemencie i chcesz wyłączyć domyślne działania. Zazwyczaj albo chcesz obsłużyć i anulować wszystkie zdarzenia dotyku, albo nie chcesz mieć dla nich żadnych metod obsługi.
Po drugie, gdy użytkownik klika element na stronie internetowej na urządzeniu mobilnym, strony, które nie zostały zaprojektowane pod kątem interakcji mobilnej, mają opóźnienie co najmniej 300 ms między zdarzeniem touchstart a przetwarzaniem zdarzeń myszy (mousedown). Można to zrobić w Chrome. W Narzędziach deweloperskich w Chrome włącz opcję „Emuluj zdarzenia dotyku”, aby przetestować interfejsy dotykowe w systemach niedotykowych.
To opóźnienie pozwala przeglądarce określić, czy użytkownik wykonuje inny gest – w szczególności powiększenie przez dwukrotne dotknięcie. Może to być oczywiście problematyczne w przypadku, gdy chcesz mieć natychmiastową reakcję na dotyk palca. Trwają prace nad ograniczeniem scenariuszy, w których to opóźnienie występuje automatycznie.
Pierwszym i najłatwiejszym sposobem uniknięcia tego opóźnienia jest „poinformowanie” przeglądarki mobilnej, że strona nie wymaga powiększania. Można to zrobić, używając stałego widocznego obszaru, np. wstawiając na stronie:
<meta name="viewport" content="width=device-width,user-scalable=no">
Nie zawsze jest to jednak odpowiednie – wyłącza to powiększanie za pomocą 2 palców, które może być wymagane ze względów związanych z dostępnością. Dlatego stosuj tę metodę z umiarkowaniem (jeśli w ogóle zdecydujesz się ją zastosować). Jeśli wyłączysz skalowanie przez użytkownika, możesz w swojej aplikacji udostępnić inny sposób zwiększenia czytelności tekstu. To opóźnienie nie dotyczy Chrome na urządzeniach klasy komputerów stacjonarnych obsługujących funkcje dotykowe ani innych przeglądarek na platformach mobilnych, gdy strona ma widoki, których nie można skalować.
#2: Zdarzenia przesunięcia kursora nie są wywoływane przez dotyk
W tym miejscu warto zauważyć, że emulacja zdarzeń myszy w interfejsie dotykowym zwykle nie obejmuje emulacji zdarzeń mousemove. Oznacza to, że jeśli tworzysz piękny element sterujący obsługiwany przez mysz, który używa zdarzeń mousemove, prawdopodobnie nie będzie on działać na urządzeniu dotykowym, chyba że dodasz też odpowiednie procedury obsługi zdarzeń touchmove.
Przeglądarki zazwyczaj automatycznie implementują odpowiednie interakcje dotykowe w elementach sterujących HTML, dlatego na przykład elementy sterujące zakresu HTML5 będą działać tylko wtedy, gdy użyjesz tych interakcji. Jeśli jednak zaimplementujesz własne elementy sterujące, prawdopodobnie nie będą one działać w przypadku interakcji typu kliknij i przeciągnij. Niektóre powszechnie używane biblioteki (np. jQueryUI) nie obsługują jeszcze natywnej obsługi interakcji dotykowych w ten sposób (chociaż w przypadku jQueryUI istnieje kilka poprawek, które rozwiązują ten problem). Był to jeden z pierwszych problemów, które napotkałem podczas aktualizacji aplikacji Web Audio Playground do obsługi dotykowej – suwaki były oparte na jQueryUI, więc nie działały z interakcjami kliknięcia i przeciągania. Przełączyłem się na ustawienia zakresu HTML5 i one działają. Oczywiście można też po prostu dodać moduły obsługi przesuwania palcem, aby aktualizować suwaki, ale jest z tym pewien problem.
3. Touchmove i MouseMove to nie to samo
Pewnym pułapką, na którą natrafiłam, jest to, że niektórzy deweloperzy wywołują te same ścieżki kodu w obsługach zdarzeń touchmove i mousemove. Działanie tych zdarzeń jest bardzo zbliżone, ale nieznacznie inne – zwłaszcza zdarzenia dotknięcia zawsze są kierowane na element, w którym użytkownik dotknie przycisku ROZPOCZNIJ, a zdarzenia myszy są kierowane na element znajdujący się obecnie po najechaniu kursorem. Dlatego mamy zdarzenia mouseover i mouseout, ale nie ma odpowiednich zdarzeń touchover i touchout – tylko touchend.
Najczęstszym problemem jest usunięcie (lub przeniesienie) elementu, który użytkownik zaczął dotykać. Wyobraź sobie na przykład karuzelę obrazów z obsługą dotykową w całej karuzeli, która obsługuje niestandardowe przewijanie. Gdy dostępne obrazy się zmieniają, usuwasz niektóre elementy <img>
i dodasz inne. Jeśli użytkownik zacznie dotykać jeden z tych obrazów, a potem go usuniesz, Twój moduł obsługi (znajdujący się w przodku elementu img) przestanie otrzymywać zdarzenia dotykowe (ponieważ są one wysyłane do celu, który nie jest już w drzewie). Wyglądać to będzie tak, jakby użytkownik trzymał palec w jednym miejscu, mimo że może go przesunąć i ostatecznie usunąć.
Oczywiście możesz uniknąć tego problemu, unikając usuwania elementów, które mają moduły obsługi dotyku (lub mają je ich przodkowie) podczas aktywnego dotyku. Innym sposobem jest rejestrowanie statycznych modułów obsługi zdarzeń touchend / touchmove zamiast czekania na zdarzenie touchstart, a następnie dodanie modułów obsługi zdarzeń touchmove / touchend / touchcancel do elementu docelowego zdarzenia touchstart (i usunięcie ich po zakończeniu / anulowaniu). Dzięki temu będziesz nadal otrzymywać zdarzenia dotyczące kliknięcia, nawet jeśli docelowy element zostanie przesunięty lub usunięty. Możesz trochę poeksperymentować tutaj – dotknij czerwonego pola i przytrzymując je, naciśnij klawisz Escape, aby usunąć je z DOM.
#4: Dotknij i :Przesuń
Metafora wskaźnika myszy oddziela pozycję kursora od aktywnego wybierania, co pozwala deweloperom używać stanów najechania kursorem, aby ukrywać i wyświetlać informacje, które mogą być istotne dla użytkowników. Jednak większość interfejsów dotykowych nie wykrywa „najeżdżania” palcem na element – dlatego wyświetlanie ważnych informacji semantycznych (np. wyskakującego okienka z pytaniem „Co to za element sterujący?”) na podstawie najeżdżania jest niedopuszczalne, chyba że zapewnisz też przyjazny dla dotykowych ekranów sposób dostępu do tych informacji. Musisz uważać, jak używasz nawigacji kursorem, aby przekazywać informacje użytkownikom.
Co ciekawe, w niektórych przypadkach interfejsy dotykowe mogą w pewnych przypadkach wywołać pseudoklasę CSS :hover. Gdy klikniesz element, stanie się on aktywny, dopóki palec jest wciśnięty, a także uzyska stan :hover. (W Internet Explorerze :hover jest aktywne tylko wtedy, gdy palec użytkownika jest na ekranie – inne przeglądarki zachowują :hover do następnego kliknięcia lub przesunięcia kursora). To dobre podejście do tworzenia menu wyskakujących w interfejsach dotykowych – efektem aktywacji elementu jest też zastosowanie stanu :hover. Na przykład:
<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>
Gdy użytkownik kliknie inny element, ten pierwszy przestaje być aktywny i stan najechania znika, tak jakby użytkownik przesunął kursor myszy z tego elementu. Możesz owinąć zawartość w elemencie <a>
, aby stała się ona też przyciskiem tab. Dzięki temu użytkownik może przełączać dodatkowe informacje przez najechanie kursorem lub kliknięcie myszką, dotknięcie ekranu lub naciśnięcie klawisza, bez konieczności korzystania z języka JavaScript. Gdy zaczęłam pracować nad Web Audio Playground, aby działał dobrze z interfejsami dotykowymi, byłam mile zaskoczona, że moje menu wyskakujące już dobrze działało na urządzeniach dotykowych, ponieważ używałam tego typu struktury.
Powyższa metoda sprawdza się zarówno w przypadku interfejsów opartych na wskaźniku myszy, jak i interfejsów dotykowych. W przeciwieństwie do atrybutów „title” (tytuł) wyświetlanych po najechaniu kursorem, które NIE będą widoczne po aktywowaniu elementu:
<img src="/awesome.png" title="this doesn't show up in touch">
#5: Dokładność panelu dotykowego w porównaniu z myszą
Chociaż myszy są odrealnione, okazuje się, że są bardzo dokładne, ponieważ system operacyjny śledzi dokładną pozycję kursora w pikselach. Z drugiej strony deweloperzy aplikacji mobilnych wiedzą, że dotyk palców na ekranie dotykowym nie jest tak dokładny, głównie ze względu na rozmiar powierzchni palca w miejscu kontaktu z ekranem (i częściowo dlatego, że palce zasłaniają ekran).
Wiele osób i firm przeprowadziło obszerne badania dotyczące projektowania aplikacji i witryn, które umożliwiają interakcję za pomocą palców. Na ten temat napisano też wiele książek. Podstawową radą jest zwiększenie rozmiaru docelowych elementów dotykowych przez zwiększenie odstępu oraz zmniejszenie prawdopodobieństwa nieprawidłowego kliknięcia przez zwiększenie marginesu między elementami. (marginesy nie uwzględnia się w wykrywaniach podczas obsługi zdarzeń dotyku i kliknięcia, ale uwzględnia się w przypadku wypełnień). Jednym z głównych rozwiązań, które musiałem wprowadzić w Web Audio Playground, było zwiększenie rozmiarów punktów połączenia, aby można było je dotykać z większą precyzją.
Wielu dostawców przeglądarek, którzy obsługują interfejsy oparte na dotyku, wprowadziło również funkcje logiczne, które pomagają kierować reklamy na właściwy element, gdy użytkownik dotyka ekranu. Pozwala to jednak zmniejszyć prawdopodobieństwo nieprawidłowych kliknięć. Mimo to zazwyczaj koryguje tylko zdarzenia kliknięcia, a nie przesuwanie (chociaż Internet Explorer zdaje się modyfikować również zdarzenia kursora w dół, przesuwania kursora i myszy).
#6: Nie pozwól, aby uchwyty dotykowe ograniczały Twoje przewijanie
Ważne jest też, by moduły obsługi dotykowe ograniczały się tylko do elementów, w których są potrzebne. Elementy dotykowe mogą mieć bardzo dużą przepustowość, dlatego ważne jest, by unikać modułów obsługi dotykowych w przypadku przewijanych elementów (ponieważ przetwarzanie może zakłócać optymalizację przeglądarki pod kątem szybkiego, bezproblemowego przewijania dotykiem – nowoczesne przeglądarki starają się przewijać w wątku GPU, ale nie jest to możliwe, jeśli muszą sprawdzać każde zdarzenie dotykowe, aby najpierw sprawdzić, czy aplikacja musi sprawdzać każde z tych elementów. Zapoznaj się z przykładem takiego zachowania.
Aby uniknąć tego problemu, warto upewnić się, że jeśli obsługujesz zdarzenia dotykowe tylko w małej części interfejsu użytkownika, tylko w nim dołączane są moduły obsługi dotykowe (a nie np.na <body>
strony). Krótko mówiąc, jak najdokładniej ogranicz ich zakres.
7. Technologia wielodotykowa
Ostatnim interesującym wyzwaniem jest to, że chociaż nazywamy to interfejsem użytkownika „dotykowym”, w rzeczywistości interfejsy API obsługują prawie zawsze wielodotykowe wprowadzanie danych, czyli umożliwiają wprowadzanie więcej niż jednego dotyku naraz. Gdy zaczniesz obsługiwać w swoich aplikacjach dotyk, weź pod uwagę, jak na aplikację może wpływać wielokrotne dotykanie.
Jeśli aplikacje tworzysz głównie za pomocą myszy, prawdopodobnie przyzwyczajasz się do tworzenia z maksymalnie jednym kursorem – systemy zwykle nie obsługują wielu kursorów myszy. W wielu aplikacjach wystarczy mapować zdarzenia dotyku na interfejs z jednym kursorem, ale większość urządzeń dotykowych dostępnych na komputerach może obsługiwać co najmniej 2 jednoczesne wejścia, a większość nowych urządzeń obsługuje co najmniej 5 jednoczesnych wejść. Jeśli tworzysz klawiaturę fortepianową na ekranie, chcesz oczywiście obsługiwać wiele jednoczesnych wejść dotykowych.
Obecnie stosowane interfejsy W3C Touch API nie mają interfejsu API, który pozwalałby określić, ile punktów styczności z ekranem obsługuje sprzęt. Dlatego musisz oszacować, ile punktów styczności z ekranem będą chcieli mieć użytkownicy. Możesz też zwrócić uwagę na to, ile punktów styczności z ekranem widzisz w praktyce, i odpowiednio do tego dostosować interfejs. Jeśli na przykład w aplikacji do gry na pianinie nigdy nie pojawia się więcej niż 2 punkty styczności z użytkownikiem, warto dodać interfejs „akordów”. Interfejs PointerEvents API ma interfejs API, który określa możliwości urządzenia.
Retusz
Mamy nadzieję, że ten artykuł dostarczył Ci wskazówek dotyczących typowych problemów związanych z wdrażaniem obsługi dotykowej i działania myszy. Ważniejsze od jakichkolwiek innych porad jest oczywiście testowanie aplikacji na komórkach, tabletach i komputerach, w których użytkownik korzysta tylko z myszki i dotyku. Jeśli nie masz urządzenia z ekranem dotykowym i myszką, skorzystaj z funkcji „Naśladowanie zdarzeń dotykowych” w Chrome, aby przetestować różne scenariusze.
Zastosowanie się do tych wskazówek jest nie tylko możliwe, ale stosunkowo łatwe, aby stworzyć angażujące interaktywne elementy, które dobrze sprawdzają się w przypadku sterowania dotykowego, wprowadzania danych za pomocą myszy, a nawet obu stylów interakcji jednocześnie.