Annó naívan azt gondoltam, hogy mobil webalkalmazás fejlesztésnél az lesz a legnagyobb gondom, hogy a mobil eszköz képernyőjén kevesebb képpont van mint egy rendes monitoron. Hát nem ez lett a legnagyobb gondom. Köztudott hogy egér és egyéb pointer híján leginkább kézzel böködünk. Ráadásul létezik duplaböködés, tehát ha kétszer gyorsan egymás után odapöccintünk akkor az csinál valamit, például felnagyítja/lekicsinyíti a weboldalt. Viszont ahhoz hogy ki lehessen találni hogy egy dupla böködésről van szó, az első böködés után kell várni egy kicsit, például 300 milliszekundumot, azaz durván egy harmad másodpercet. Annak idején, amikor még nem voltak multitouch kijelzők, valószínűleg jó ötletnek tűnt.
Ez az egyharmad másodperc éppen elég rá, hogy szétcsessze az ún. felhasználói élményt. Odapöccintek és kis késéssel reagál a webapp. Naívabb fejlesztők még azt is hihetik hogy "lassú a jávaszkript". Ez persze statikus weboldalaknál nem gáz, csak olyan mobilos webalkalmazásoknál, amik desktopos alkalmazásokra akarnak hasonlítani. Azaz megnyomsz egy virtuális gombot és elvárható lenne, hogy azonnal történik valami, azonnal van visszacsatolás.
Vannak megoldások. Elsőnek a kézenfekvőnek tűnő JQuery Mobile-t próbáltam ki, azon belül is a vclick event-et. A 300ms késést megszünteti, de vannak vele gondok. Ha gyorsan egymás után tapiznak két különböző helyre, pl. A-ra, aztán B-re, akkor az első tapizás megduplázódik, tehát AAB történik. Ha tapiznak valahova és az esemény kezelése közben megváltozik a tapizott rész tartalma, akkor az új tartalomra is le fog menni egy esemény. Ezen kívül van egy késleltetett effekt, ami miatt bekereteződik, kiszíneződik pár tizedmásodpercre a megérintett elem, de akkorra már valójában rég lezajlott az eseménykezelés. Ez az effekt igencsak esetlen, de ki lehet küszöbölni egy kis css-sel: body { -webkit-touch-callout: none; -webkit-text-size-adjust: none; -webkit-user-select: none; -webkit-highlight: none; -webkit-tap-highlight-color: rgba(0,0,0,0); }
Visszatérve a duplázódó eseményre, megpróbáltam egy szűrőt tenni az eseménykezelő elő. Ha két eseményt érzékel gyorsan egymás után (bizonyos T időn belül) azonos helyről, akkor a másodikat eldobja. Sajnos ez nem működik annyira jól, mert ha T-t túl kicsire veszem (100ms) akkor továbbra is előfordul a duplázódó esemény, ha viszont túl nagyra veszem (150-200ms) akkor nem lehet gyorsan egymás után ugyanoda tapizni, mert a második ki lesz szűrve, felhasználói kifejezéssel “nem veszi be”. Ez roppant kényelmetlen, felhasználói élmény romboló hatású. Fürge ujjú user-ek olyan gyorsan tudnak duplázni, hogy a T=100ms is túl lassú nekik, tehát nem lehet eldönteni, hogy a második tapizás egy nem kívánt esemény, vagy a user valóban tapizott másodszor. Szóval ez az irány nem adott tökéletes megoldást.
Craig Buckler ebben a blogposztban leírt további öt megoldást a problémára (2014 januárjában), amiből az első négy nem igazán alkalmazható minden esetben, mert böngészőspecifikus. Az ötödik megoldás lényege, hogy érintőképernyős eszközöknél a touchstart és touchend eseményekre figyeljünk, ne a click eseményre, de ezzel is vannak gondok: fel kell ismerni és kiszűrni a görgetést, swipe-olást, ráadásul a rendes click eseményt is le kéne kezelni -gondolva az egeres eszközökre- de azért nem kellene duplán kezelni a user interakciókat. Craig még ajánlott két javascript library-t, amiben elvileg jól megírták helyettünk ezt a touchstart, touchend kezelést. Ezek közül a FastClick-et próbáltam ki, de ugyanúgy produkálta a duplázódóst bevitelt mint a JQueryMobile vclick-je.
Az én konkrét webalkalmazásomban szerencsére nincs swipe és mindenféle extra dolog, csak sima klikkelés vagy tapizás. Hirtelen ötlettől vezérelve kipróbáltam a touchstart-ot, amihez még JQueryMobile sem kell. Asztali böngészőben egérrel természetesen nem működik, de mobilon villámgyors és nem csinálja a duplázós bakit sem. Azt eldönteni, hogy érintőképernyővel van-e dolgunk vagy egérrel lehetetlen, szóval ez egy “no go” irány. Különben is, lehetséges hogy egér IS van és érintőképernyő IS. De mi lenne ha egy click eseménykezelőt is rátűznék az elemekre, ami ellenőrzi hogy volt-e nem sokkal előtte touchstart. Ha volt touchstart, akkor már lekezeltük, stornó az egész, de ha nem volt akkor egérkattintásról van szó, tehát le kell kezelni. A Stackoverflow-n utólag szétnézve többen is ajánlják ezt a megoldást. Ha T-t 1000ms-re veszem, akkor látszólag működik, gyors és megszűnik a duplázás, egyedül az a jelenség marad meg, hogy ha változik a tartalom a tapizott terület alatt, akkor generálódik még egy fölösleges esemény az új tartalom eseménykezelői miatt. Ezt a jelenséget a JQuery Mobile vclick event doksijában is leírják és azt javasolják, hogy az olyan elemekre, amik megváltoztathatják a tartalmat, inkább sima click handler-t aggassunk. De máshogy is meg lehet oldani. Az én webapp-omban csak teljes oldalcsere történik időnként. Egy ilyen oldalcserénél letiltom a click event-et 1 másodpercre egy timestamp rögzítésével.
Csináltam ennek a témának egyébként egy demóoldal-t, amit főleg mobiltelóval lehet nyomogatni, de asztali böngészőben sem szabadna teljesen szétszállnia. Lehet számokat beírogatni, két mezőbe, amiket ki lehet választani. Hogy ha a number mezőre nyomunk amikor már kiválasztottuk, akkor feljön egy másik oldal, egyébként meg az egész nem csinál semmit. Egyelőre csak a saját Androidos telómon (Motorola Defy+) próbáltam ki default böngészővel, de azért remélem általában működik. Ha valaki kipróbálja egyéb telón és kommentbe beírja hogy működik vagy gáz van vele, az welcome. A legértékesebb visszajelzések és javaslatok kommentelőjét meghívom egy sörre az egyik következő JUM-on.
Jó sokat szívtam ezzel a témával és még sejtem hogy nincs vége, dehát a felhasználói élményért mindent.