دوباره با هم برای اولین بار
مقدمه
برای نزدیک به سی سال، تجربیات رایانه رومیزی حول یک صفحه کلید و ماوس یا صفحه لمسی به عنوان دستگاه های ورودی اصلی کاربر متمرکز شده است. با این حال، در دهه گذشته، تلفنهای هوشمند و تبلتها الگوی تعاملی جدیدی را به ارمغان آوردهاند: لمس. با معرفی دستگاههای ویندوز 8 مجهز به لمس، و اکنون با عرضه Chromebook Pixel با قابلیت لمسی عالی، لمس اکنون به بخشی از تجربه مورد انتظار دسکتاپ تبدیل شده است. یکی از بزرگترین چالشها ایجاد تجربیاتی است که نه تنها بر روی دستگاههای لمسی و دستگاههای ماوس، بلکه در این دستگاهها نیز کار میکنند که در آن کاربر از هر دو روش ورودی - گاهی اوقات به طور همزمان - استفاده میکند!
این مقاله به شما کمک میکند بفهمید که چگونه قابلیتهای لمسی در مرورگر تعبیه شدهاند، چگونه میتوانید این مکانیسم رابط جدید را در برنامههای موجود خود ادغام کنید و چگونه لمس میتواند به خوبی با ورودی ماوس بازی کند.
وضعیت لمس در بستر وب
آیفون اولین پلتفرم محبوبی بود که دارای APIهای لمسی اختصاصی در مرورگر وب بود. چندین فروشنده مرورگر دیگر رابطهای API مشابهی را ایجاد کردهاند که برای سازگاری با پیادهسازی iOS ساخته شدهاند، که اکنون با مشخصات "رویدادهای لمسی نسخه 1" توضیح داده شده است. رویدادهای لمسی توسط کروم و فایرفاکس روی دسکتاپ و توسط سافاری در iOS و کروم و مرورگر اندروید در اندروید و همچنین سایر مرورگرهای تلفن همراه مانند مرورگر Blackberry پشتیبانی میشوند.
همکار من Boris Smus یک آموزش عالی برای HTML5Rocks در مورد رویدادهای لمسی نوشت که اگر قبلاً رویدادهای Touch را نگاه نکرده باشید همچنان راه خوبی برای شروع است. در واقع، اگر قبلاً با رویدادهای لمسی کار نکردهاید، قبل از ادامه، همین الان آن مقاله را بخوانید. برو من صبر میکنم
همه چیز تمام شد؟ اکنون که شما یک پایه اساسی در رویدادهای لمسی دارید، چالش نوشتن تعاملات لمسی این است که تعاملات لمسی میتواند با رویدادهای ماوس (و پد لمسی شبیهسازیکننده ماوس و ترکبال) کاملاً متفاوت باشد - و اگرچه رابطهای لمسی معمولاً سعی میکنند موشها را شبیهسازی کنند، این شبیهسازی کامل یا کامل نیست. شما واقعاً باید از طریق هر دو سبک تعامل کار کنید و ممکن است مجبور شوید هر رابط را به طور مستقل پشتیبانی کنید.
مهمتر از همه: کاربر ممکن است لمس و ماوس داشته باشد
بسیاری از توسعه دهندگان سایت هایی ساخته اند که به طور ایستا تشخیص می دهند که آیا یک محیط از رویدادهای لمسی پشتیبانی می کند یا خیر، و سپس فرض می کنند که آنها فقط نیاز به پشتیبانی از رویدادهای لمسی (و نه ماوس) دارند. اکنون این یک فرض معیوب است - در عوض، فقط به دلیل وجود رویدادهای لمسی به این معنی نیست که کاربر در درجه اول از آن دستگاه ورودی لمسی استفاده می کند. دستگاههایی مانند Chromebook Pixel و برخی از لپتاپهای Windows 8 اکنون از هر دو روش ورودی ماوس و لمسی پشتیبانی میکنند و در آیندهای نزدیک موارد بیشتری نیز از آن پشتیبانی خواهند کرد. در این دستگاهها، استفاده از ماوس و صفحه لمسی برای کاربران برای تعامل با برنامهها کاملاً طبیعی است، بنابراین «پشتیبانی از لمس» با «نیازی به پشتیبانی ماوس» یکی نیست. شما نمی توانید مشکل را اینگونه در نظر بگیرید که "من باید دو سبک تعامل متفاوت بنویسم و بین آنها جابجا شوم"، باید به این فکر کنید که چگونه هر دو تعامل با هم و به طور مستقل کار می کنند. در Chromebook Pixel خود، اغلب از پد لمسی استفاده میکنم، اما همچنین صفحه را لمس میکنم - در همان برنامه یا صفحه، هر کاری را که در آن لحظه طبیعیتر به نظر میرسد انجام میدهم. از سوی دیگر، برخی از کاربران لپ تاپ با صفحه لمسی به ندرت از صفحه نمایش لمسی استفاده می کنند - بنابراین وجود ورودی لمسی نباید کنترل ماوس را غیرفعال یا مانع شود.
متأسفانه، دانستن اینکه آیا محیط مرورگر کاربر از ورودی لمسی پشتیبانی میکند یا خیر، دشوار است. در حالت ایده آل، یک مرورگر روی یک ماشین دسکتاپ همیشه پشتیبانی از رویدادهای لمسی را نشان می دهد، بنابراین یک صفحه نمایش لمسی می تواند در هر زمان وصل شود (مثلاً اگر صفحه لمسی متصل شده از طریق KVM در دسترس باشد). به همه این دلایل، برنامه های شما نباید سعی کنند بین لمس و ماوس جابجا شوند - فقط از هر دو پشتیبانی کنید!
پشتیبانی از ماوس و لمس با هم
شماره 1 - کلیک کردن و ضربه زدن - ترتیب "طبیعی" چیزها
اولین مشکل این است که رابطهای لمسی معمولاً سعی میکنند کلیکهای ماوس را شبیهسازی کنند - بدیهی است که رابطهای لمسی باید روی برنامههایی کار کنند که قبلاً فقط با رویدادهای ماوس تعامل داشتهاند! میتوانید از این بهعنوان میانبر استفاده کنید - زیرا رویدادهای «کلیک» همچنان فعال میشوند، چه کاربر با ماوس کلیک کند یا انگشت خود را روی صفحه ضربه بزند. با این حال، چند مشکل در این میانبر وجود دارد.
ابتدا، هنگام طراحی تعاملات لمسی پیشرفتهتر باید مراقب باشید: وقتی کاربر از ماوس استفاده میکند، از طریق یک رویداد کلیک پاسخ میدهد، اما وقتی کاربر صفحه را لمس میکند، رویدادهای لمس و کلیک هر دو رخ میدهند. برای یک کلیک ترتیب رویدادها به صورت زیر است:
- شروع لمسی
- حرکت لمسی
- لمسی
- ماوس
- حرکت ماوس
- ماوس پایین
- موس
- کلیک کنید
البته این بدان معنی است که اگر رویدادهای لمسی مانند شروع لمسی را پردازش می کنید، باید مطمئن شوید که ماوس و/یا رویداد کلیک مربوطه را نیز پردازش نمی کنید. اگر بتوانید رویدادهای لمسی را لغو کنید (فراخوانی preventDefault() در کنترل کننده رویداد)، هیچ رویدادی از ماوس برای لمس ایجاد نخواهد شد. یکی از مهمترین قوانین کنترل کننده های لمسی این است:
با این حال، این همچنین از سایر رفتارهای پیشفرض مرورگر (مانند پیمایش) جلوگیری میکند - اگرچه معمولاً رویداد لمسی را کاملاً در کنترلر خود مدیریت میکنید و میخواهید اقدامات پیشفرض را غیرفعال کنید. به طور کلی، یا می خواهید همه رویدادهای لمسی را مدیریت کرده و لغو کنید، یا از داشتن یک کنترل کننده برای آن رویداد اجتناب کنید.
ثانیاً، هنگامی که کاربر روی یک عنصر در یک صفحه وب در دستگاه تلفن همراه ضربه میزند، صفحاتی که برای تعامل با تلفن همراه طراحی نشدهاند، حداقل 300 میلیثانیه بین رویداد شروع لمس و پردازش رویدادهای ماوس (دانلود کردن ماوس) تأخیر دارند. این کار را میتوان با استفاده از Chrome انجام داد، میتوانید «تقلید رویدادهای لمسی» را در ابزارهای برنامهنویس Chrome روشن کنید تا به شما کمک کند رابطهای لمسی را در یک سیستم غیرلمسی آزمایش کنید!
این تأخیر به این منظور است که مرورگر زمان تعیین کند که آیا کاربر در حال انجام حرکت دیگری است - به ویژه، بزرگنمایی با دو ضربه. بدیهی است که در مواردی که می خواهید به لمس انگشت پاسخ آنی داشته باشید، این می تواند مشکل ساز باشد. تلاش برای محدود کردن سناریوهایی که در آن این تأخیر به طور خودکار رخ می دهد، در حال انجام است.
اولین و ساده ترین راه برای جلوگیری از این تاخیر این است که به مرورگر تلفن همراه بگویید که صفحه شما نیازی به بزرگنمایی ندارد - این کار را می توان با استفاده از یک viewport ثابت انجام داد، به عنوان مثال با قرار دادن در صفحه خود:
<meta name="viewport" content="width=device-width,user-scalable=no">
البته این همیشه مناسب نیست - این کار زوم کردن را غیرفعال می کند، که ممکن است به دلایل دسترسی لازم باشد، بنابراین اگر اصلاً از آن استفاده نکنید (اگر مقیاس کاربر را غیرفعال می کنید، ممکن است بخواهید راه دیگری برای افزایش خوانایی متن در برنامه خود ارائه دهید). همچنین، برای Chrome در دستگاههای کلاس دسکتاپ که از لمس پشتیبانی میکنند، و سایر مرورگرها در پلتفرمهای تلفن همراه که صفحه دارای پورتهای نمایشی است که مقیاسپذیر نیستند، این تأخیر اعمال نمیشود.
شماره 2: رویدادهای Mousemove با لمس فعال نمی شوند
در این مرحله توجه به این نکته مهم است که تقلید رویدادهای ماوس در یک رابط لمسی معمولاً به شبیهسازی رویدادهای حرکت ماوس گسترش نمییابد - بنابراین اگر یک کنترل زیبای مبتنی بر ماوس بسازید که از رویدادهای ماوس استفاده میکند، احتمالاً با یک دستگاه لمسی کار نمیکند مگر اینکه به طور خاص کنترلکنندههای لمسی را نیز اضافه کنید.
مرورگرها معمولاً به طور خودکار تعامل مناسب را برای تعاملات لمسی روی کنترلهای HTML پیادهسازی میکنند - بنابراین، برای مثال، کنترلهای محدوده HTML5 فقط زمانی کار میکنند که از تعاملات لمسی استفاده میکنید. با این حال، اگر کنترلهای خود را پیادهسازی کرده باشید، احتمالاً روی تعاملهای نوع کلیک و کشیدن کار نخواهند کرد. در واقع، برخی از کتابخانههای رایج (مانند jQueryUI) هنوز به صورت بومی از تعاملات لمسی به این روش پشتیبانی نمیکنند (اگرچه برای jQueryUI، چندین اصلاحات میمون وصله برای این مشکل وجود دارد). این یکی از اولین مشکلاتی بود که هنگام ارتقاء برنامه Web Audio Playground برای کار با لمس با آن مواجه شدم - لغزنده ها مبتنی بر jQueryUI بودند، بنابراین با تعاملات کلیک و کشیدن کار نمی کردند. من به کنترل های HTML5 Range تغییر دادم و آنها کار کردند. البته میتوانستم بهسادگی کنترلکنندههای لمسی را برای بهروزرسانی لغزندهها اضافه کنم، اما یک مشکل در آن وجود دارد…
شماره 3: حرکت لمسی و حرکت ماوس یکسان نیستند
تلهای که چند توسعهدهنده در آن گرفتار شدهام این است که کنترلکنندههای حرکت لمسی و ماوس به مسیرهای کد مشابهی تماس میگیرند. رفتار این رویدادها بسیار نزدیک است، اما به طور ماهرانه متفاوت است - به ویژه، رویدادهای لمسی همیشه عنصری را هدف قرار می دهند که آن نقطه شروع شد، در حالی که رویدادهای ماوس عنصری را که در حال حاضر در زیر نشانگر ماوس قرار دارد هدف قرار می دهند. به همین دلیل است که ما رویدادهای موس و موس را داریم، اما هیچ رویداد لمسی و لمسی مربوطه وجود ندارد - فقط لمس کردن.
رایجترین روشی که میتواند شما را نیش بزند این است که عنصری را که کاربر شروع به لمس آن کرده است حذف کنید (یا تغییر مکان دهید). برای مثال، یک چرخ فلک تصویر را با یک کنترلر لمسی در کل چرخ فلک تصور کنید تا از رفتار پیمایش سفارشی پشتیبانی کند. با تغییر تصاویر موجود، برخی از عناصر <img>
را حذف کرده و برخی دیگر را اضافه میکنید. اگر کاربر شروع به لمس یکی از آن تصاویر کرد و سپس آن را حذف کردید، کنترلر شما (که روی یکی از اجداد عنصر img است) دریافت رویدادهای لمسی را متوقف میکند (زیرا به هدفی فرستاده میشوند که دیگر در درخت نیست) - به نظر میرسد کاربر انگشت خود را در یک مکان نگه داشته است، حتی اگر ممکن است آن را حرکت داده باشد و در نهایت آن را برداشته باشد.
البته می توانید با اجتناب از حذف عناصری که دارای کنترل کننده لمسی هستند (یا نیاکانی دارند) در حالی که لمس فعال است، از این مشکل جلوگیری کنید. متناوبا، بهترین راهنما به جای ثبت کنترل کننده های لمسی/لمسی ثابت است، صبر کنید تا یک رویداد شروع لمسی دریافت کنید و سپس کنترل کننده های لمسی/لمسی/لغو لغو را به هدف رویداد شروع لمسی اضافه کنید (و در پایان/لغو آنها را حذف کنید). به این ترتیب حتی اگر عنصر هدف جابجا/حذف شود، به دریافت رویدادها برای لمس ادامه خواهید داد. میتوانید در اینجا کمی با آن بازی کنید - کادر قرمز را لمس کرده و در حالی که نگهداشتهاید، escape را فشار دهید تا آن را از DOM حذف کنید.
شماره 4: لمس کنید و: شناور کنید
استعاره اشاره گر ماوس موقعیت مکان نما را از انتخاب فعال جدا می کند و این به توسعه دهندگان اجازه می دهد تا از حالت های شناور برای پنهان کردن و نمایش اطلاعاتی که ممکن است برای کاربران مناسب باشد استفاده کنند. با این حال، اکثر رابطهای لمسی در حال حاضر یک انگشت را که روی یک هدف قرار میگیرد تشخیص نمیدهند - بنابراین ارائه اطلاعات مهم معنایی (مثلاً ارائه پنجره بازشو «این کنترل چیست؟») بر اساس شناور کردن، خیر است، مگر اینکه روشی لمسی برای دسترسی به این اطلاعات ارائه دهید. باید مراقب نحوه استفاده از شناور برای انتقال اطلاعات به کاربران باشید.
به اندازه کافی جالب توجه است که CSS :hover pseudoclass CAN در برخی موارد می تواند توسط رابط های لمسی فعال شود - ضربه زدن روی یک عنصر آن را در حالی که انگشت پایین است فعال می کند و همچنین حالت :hover را به دست می آورد. (در اینترنت اکسپلورر، :hover فقط زمانی که انگشت کاربر پایین است فعال است - سایر مرورگرها :hover را تا ضربه بعدی یا حرکت ماوس فعال نگه میدارند.) این روش خوبی برای کارکرد منوهای بازشو روی رابطهای لمسی است - یکی از عوارض جانبی فعال کردن یک عنصر این است که حالت :hover نیز اعمال میشود. به عنوان مثال:
<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>
هنگامی که عنصر دیگری ضربه می زند، عنصر دیگر فعال نیست، و حالت شناور ناپدید می شود، درست مثل اینکه کاربر از نشانگر ماوس استفاده کرده و آن را از عنصر خارج کرده است. ممکن است بخواهید محتوا را در یک عنصر <a>
بپیچید تا آن را به یک Tabstop نیز تبدیل کنید - به این ترتیب کاربر میتواند اطلاعات اضافی را روی نشان دادن یا کلیک ماوس، ضربه زدن لمسی یا فشار کلید بدون نیاز به جاوا اسکریپت تغییر دهد. وقتی شروع به کار کردم تا زمینه بازی صوتی وب خود را به خوبی با رابط های لمسی که منوهای بازشو من قبلاً روی لمس خوب کار می کردند، شروع کردم، شگفت زده شدم، زیرا من از این نوع ساختار استفاده کرده بودم!
روش فوق برای رابط های مبتنی بر اشاره گر ماوس و همچنین برای رابط های لمسی به خوبی کار می کند. این برخلاف استفاده از ویژگیهای "عنوان" در شناور است، که وقتی عنصر فعال میشود نشان داده نمیشود:
<img src="/awesome.png" title="this doesn't show up in touch">
شماره 5: لمس در مقابل دقت ماوس
در حالی که موشها از واقعیت جدایی مفهومی دارند، به نظر میرسد که بسیار دقیق هستند، زیرا سیستم عامل زیربنایی به طور کلی دقت پیکسل دقیق مکاننما را ردیابی میکند. از سوی دیگر، توسعهدهندگان موبایل یاد گرفتهاند که لمس انگشت روی صفحه لمسی، بیشتر به دلیل اندازه سطح انگشت هنگام تماس با صفحه نمایش (و تا حدی به این دلیل که انگشتان شما مانع از نمایشگر میشوند) دقیق نیستند.
بسیاری از افراد و شرکتها تحقیقات گستردهای در مورد نحوه طراحی اپلیکیشنها و سایتهایی انجام دادهاند که تعامل مبتنی بر انگشت را در خود جای میدهند و کتابهای زیادی در این زمینه نوشته شده است. توصیه اصلی این است که اندازه اهداف لمسی را با افزایش بالشتک افزایش دهید و با افزایش حاشیه بین عناصر، احتمال ضربه های نادرست را کاهش دهید. (حاشیهها در مدیریت تشخیص ضربه رویدادهای لمس و کلیک گنجانده نمیشوند، در حالی که padding است.) یکی از راهحلهای اصلی که من باید در Web Audio Playground انجام میدادم، افزایش اندازه نقاط اتصال بود تا راحتتر با دقت لمس شوند.
بسیاری از فروشندگان مرورگر که رابطهای مبتنی بر لمس را مدیریت میکنند، منطق را به مرورگر وارد کردهاند تا به هدف قرار دادن عنصر صحیح زمانی که کاربر صفحه را لمس میکند و احتمال کلیکهای نادرست را کاهش میدهد - اگرچه این معمولاً فقط رویدادهای کلیک را تصحیح میکند، نه حرکت را (اگرچه به نظر میرسد اینترنت اکسپلورر رویدادهای حذف ماوس/موشواره را نیز تغییر میدهد).
شماره 6: کنترل کننده های لمسی را محدود نگه دارید، در غیر این صورت آنها اسکرول شما را خراب می کنند
همچنین مهم است که کنترل کننده های لمسی را فقط به عناصری که به آنها نیاز دارید محدود کنید. عناصر لمسی میتوانند پهنای باند بسیار بالایی داشته باشند، بنابراین مهم است که از کنترلکنندههای لمسی در عناصر پیمایش اجتناب کنید (زیرا پردازش شما ممکن است با بهینهسازی مرورگر برای پیمایش سریع لمسی بدون جاک تداخل داشته باشد - مرورگرهای مدرن سعی میکنند روی یک رشته GPU پیمایش کنند، اما اگر مجبور باشند ابتدا با جاوا اسکریپت بررسی کنند تا ببینند آیا هر رویداد لمسی توسط برنامه انجام میشود، این غیرممکن است). می توانید نمونه ای از این رفتار را بررسی کنید.
یکی از راهنماییهایی که باید برای جلوگیری از این مشکل دنبال کنید این است که مطمئن شوید اگر فقط رویدادهای لمسی را در بخش کوچکی از رابط کاربری خود مدیریت میکنید، فقط کنترلکنندههای لمسی را در آنجا وصل میکنید (نه، به عنوان مثال، در <body>
صفحه). به طور خلاصه، دامنه کنترل کننده های لمسی خود را تا حد امکان محدود کنید.
شماره 7: چند لمسی
چالش جالب آخر این است که اگرچه ما از آن به عنوان رابط کاربری "لمس" یاد میکنیم، تقریباً در سراسر جهان پشتیبانی از Multi-touch است - یعنی APIها بیش از یک ورودی لمسی را در یک زمان ارائه میدهند. همانطور که شروع به پشتیبانی از لمس در برنامه های خود می کنید، باید در نظر بگیرید که چگونه لمس های متعدد ممکن است بر برنامه شما تأثیر بگذارد.
اگر در حال ساخت برنامههایی بودهاید که عمدتاً توسط ماوس هدایت میشوند، پس عادت کردهاید که حداکثر با یک نقطه مکاننما بسازید - سیستمها معمولاً از چندین نشانگر ماوس پشتیبانی نمیکنند. برای بسیاری از برنامهها، شما فقط رویدادهای لمسی را به یک رابط مکاننما نگاشت میکنید، اما بیشتر سختافزارهایی که برای ورودی لمسی دسکتاپ دیدهایم میتوانند حداقل ۲ ورودی همزمان را مدیریت کنند، و به نظر میرسد اکثر سختافزارهای جدید حداقل از ۵ ورودی همزمان پشتیبانی میکنند. البته برای توسعه یک صفحه کلید پیانو روی صفحه ، باید بتوانید از چندین ورودی لمسی همزمان پشتیبانی کنید.
APIهای لمسی W3C که در حال حاضر پیادهسازی شدهاند، API ندارند تا مشخص کنند که سختافزار چند نقطه لمسی را پشتیبانی میکند، بنابراین باید از بهترین تخمین خود برای تعداد نقاط لمسی که کاربران شما میخواهند استفاده کنید - یا، البته، به تعداد نقاط لمسی که در عمل میبینید توجه کنید و تطبیق دهید. به عنوان مثال، در یک برنامه پیانو، اگر هرگز بیش از دو نقطه لمسی نمی بینید، ممکن است بخواهید چند "آکورد" UI اضافه کنید. PointerEvents API یک API برای تعیین قابلیت های دستگاه دارد.
لمس کردن
امیدواریم این مقاله به شما راهنمایی هایی در مورد چالش های رایج در پیاده سازی لمس در کنار تعاملات ماوس داده باشد. البته مهمتر از هر توصیه دیگری این است که باید برنامه خود را روی موبایل، تبلت و محیط های دسکتاپ ترکیبی موس و لمسی تست کنید. اگر سختافزار لمسی + ماوس ندارید، از " Emulate touch events " Chrome استفاده کنید تا به شما در آزمایش سناریوهای مختلف کمک کند.
ایجاد تجربیات تعاملی جذابی که همزمان با ورودی لمسی، ورودی ماوس و حتی هر دو سبک تعامل به خوبی کار میکنند، نه تنها ممکن است، بلکه نسبتاً آسان است، پیروی از این دستورالعملها.