لمس و ماوس

دوباره با هم برای اولین بار

مقدمه

برای نزدیک به سی سال، تجربیات رایانه رومیزی حول یک صفحه کلید و ماوس یا صفحه لمسی به عنوان دستگاه های ورودی اصلی کاربر متمرکز شده است. با این حال، در دهه گذشته، تلفن‌های هوشمند و تبلت‌ها الگوی تعاملی جدیدی را به ارمغان آورده‌اند: لمس. با معرفی دستگاه‌های ویندوز 8 مجهز به لمس، و اکنون با عرضه Chromebook Pixel با قابلیت لمسی عالی، لمس اکنون به بخشی از تجربه مورد انتظار دسکتاپ تبدیل شده است. یکی از بزرگ‌ترین چالش‌ها ایجاد تجربیاتی است که نه تنها بر روی دستگاه‌های لمسی و دستگاه‌های ماوس، بلکه در این دستگاه‌ها نیز کار می‌کنند که در آن کاربر از هر دو روش ورودی - گاهی اوقات به طور همزمان - استفاده می‌کند!

این مقاله به شما کمک می‌کند بفهمید که چگونه قابلیت‌های لمسی در مرورگر تعبیه شده‌اند، چگونه می‌توانید این مکانیسم رابط جدید را در برنامه‌های موجود خود ادغام کنید و چگونه لمس می‌تواند به خوبی با ورودی ماوس بازی کند.

وضعیت لمس در بستر وب

آیفون اولین پلتفرم محبوبی بود که دارای APIهای لمسی اختصاصی در مرورگر وب بود. چندین فروشنده مرورگر دیگر رابط‌های API مشابهی را ایجاد کرده‌اند که برای سازگاری با پیاده‌سازی iOS ساخته شده‌اند، که اکنون با مشخصات "رویدادهای لمسی نسخه 1" توضیح داده شده است. رویدادهای لمسی توسط کروم و فایرفاکس روی دسکتاپ و توسط سافاری در iOS و کروم و مرورگر اندروید در اندروید و همچنین سایر مرورگرهای تلفن همراه مانند مرورگر Blackberry پشتیبانی می‌شوند.

همکار من Boris Smus یک آموزش عالی برای HTML5Rocks در مورد رویدادهای لمسی نوشت که اگر قبلاً رویدادهای Touch را نگاه نکرده باشید همچنان راه خوبی برای شروع است. در واقع، اگر قبلاً با رویدادهای لمسی کار نکرده‌اید، قبل از ادامه، همین الان آن مقاله را بخوانید. برو من صبر میکنم

همه چیز تمام شد؟ اکنون که شما یک پایه اساسی در رویدادهای لمسی دارید، چالش نوشتن تعاملات لمسی این است که فعل و انفعالات لمسی می تواند کمی متفاوت از رویدادهای ماوس (و شبیه ساز ماوس و پد لمسی) باشد - و اگرچه رابط های لمسی معمولا سعی می کنند از موش ها تقلید کنید، این شبیه سازی کامل یا کامل نیست. شما واقعاً باید از طریق هر دو سبک تعامل کار کنید و ممکن است مجبور شوید هر رابط را به طور مستقل پشتیبانی کنید.

مهمتر از همه: کاربر ممکن است لمس و ماوس داشته باشد

بسیاری از توسعه دهندگان سایت هایی ساخته اند که به طور ایستا تشخیص می دهند که آیا یک محیط از رویدادهای لمسی پشتیبانی می کند یا خیر، و سپس فرض می کنند که آنها فقط نیاز به پشتیبانی از رویدادهای لمسی (و نه ماوس) دارند. اکنون این یک فرض معیوب است - در عوض، فقط به دلیل وجود رویدادهای لمسی به این معنی نیست که کاربر در درجه اول از آن دستگاه ورودی لمسی استفاده می کند. دستگاه‌هایی مانند Chromebook Pixel و برخی از لپ‌تاپ‌های Windows 8 اکنون از هر دو روش ورودی ماوس و لمسی پشتیبانی می‌کنند و در آینده‌ای نزدیک موارد بیشتری نیز از آن پشتیبانی خواهند کرد. در این دستگاه‌ها، استفاده از ماوس و صفحه لمسی برای کاربران برای تعامل با برنامه‌ها کاملاً طبیعی است، بنابراین «پشتیبانی از لمس» با «نیازی به پشتیبانی ماوس» یکی نیست. شما نمی توانید مشکل را اینگونه در نظر بگیرید که "من باید دو سبک تعامل متفاوت بنویسم و ​​بین آنها جابجا شوم"، باید به این فکر کنید که چگونه هر دو تعامل با هم و به طور مستقل کار می کنند. در Chromebook Pixel خود، اغلب از پد لمسی استفاده می‌کنم، اما همچنین صفحه را لمس می‌کنم - در همان برنامه یا صفحه، هر کاری را که در آن لحظه طبیعی‌تر به نظر می‌رسد انجام می‌دهم. از سوی دیگر، برخی از کاربران لپ تاپ با صفحه لمسی به ندرت از صفحه نمایش لمسی استفاده می کنند - بنابراین وجود ورودی لمسی نباید کنترل ماوس را غیرفعال یا مانع شود.

متأسفانه، دانستن اینکه آیا محیط مرورگر کاربر از ورودی لمسی پشتیبانی می‌کند یا خیر، دشوار است. در حالت ایده آل، یک مرورگر روی یک ماشین دسکتاپ همیشه پشتیبانی از رویدادهای لمسی را نشان می دهد، بنابراین یک صفحه نمایش لمسی می تواند در هر زمان وصل شود (مثلاً اگر صفحه لمسی متصل شده از طریق KVM در دسترس باشد). به همه این دلایل، برنامه های شما نباید سعی کنند بین لمس و ماوس جابجا شوند - فقط از هر دو پشتیبانی کنید!

پشتیبانی از ماوس و لمس با هم

شماره 1 - کلیک کردن و ضربه زدن - ترتیب "طبیعی" چیزها

اولین مشکل این است که رابط‌های لمسی معمولاً سعی می‌کنند کلیک‌های ماوس را شبیه‌سازی کنند - بدیهی است که رابط‌های لمسی باید روی برنامه‌هایی کار کنند که قبلاً فقط با رویدادهای ماوس تعامل داشته‌اند! می‌توانید از این به‌عنوان میان‌بر استفاده کنید - زیرا رویدادهای «کلیک» همچنان فعال می‌شوند، چه کاربر با ماوس کلیک کند یا انگشت خود را روی صفحه ضربه بزند. با این حال، چند مشکل در این میانبر وجود دارد.

ابتدا، هنگام طراحی تعاملات لمسی پیشرفته‌تر باید مراقب باشید: وقتی کاربر از ماوس استفاده می‌کند، از طریق یک رویداد کلیک پاسخ می‌دهد، اما وقتی کاربر صفحه را لمس می‌کند، رویدادهای لمس و کلیک هر دو رخ می‌دهند. برای یک کلیک ترتیب رویدادها به صورت زیر است:

  1. شروع لمسی
  2. حرکت لمسی
  3. لمسی
  4. ماوس
  5. حرکت ماوس
  6. ماوس پایین
  7. موس
  8. کلیک کنید

البته این بدان معنی است که اگر رویدادهای لمسی مانند شروع لمسی را پردازش می کنید، باید مطمئن شوید که ماوس و/یا رویداد کلیک مربوطه را نیز پردازش نمی کنید. اگر بتوانید رویدادهای لمسی را لغو کنید (فراخوانی preventDefault() در کنترل کننده رویداد)، هیچ رویدادی از ماوس برای لمس ایجاد نخواهد شد. یکی از مهمترین قوانین کنترل کننده های لمسی این است:

با این حال، این همچنین از سایر رفتارهای پیش‌فرض مرورگر (مانند پیمایش) جلوگیری می‌کند - اگرچه معمولاً رویداد لمسی را کاملاً در کنترلر خود مدیریت می‌کنید و می‌خواهید اقدامات پیش‌فرض را غیرفعال کنید. به طور کلی، یا می خواهید همه رویدادهای لمسی را مدیریت کرده و لغو کنید، یا از داشتن یک کنترل کننده برای آن رویداد اجتناب کنید.

ثانیاً، هنگامی که کاربر روی یک عنصر در یک صفحه وب در دستگاه تلفن همراه ضربه می‌زند، صفحاتی که برای تعامل با تلفن همراه طراحی نشده‌اند، حداقل 300 میلی‌ثانیه بین رویداد شروع لمس و پردازش رویدادهای ماوس (دانلود کردن ماوس) تأخیر دارند. این کار را می‌توان با استفاده از Chrome انجام داد، می‌توانید «تقلید رویدادهای لمسی» را در ابزارهای برنامه‌نویس Chrome روشن کنید تا به شما کمک کند رابط‌های لمسی را در یک سیستم غیرلمسی آزمایش کنید!

این تأخیر به این منظور است که مرورگر زمان تعیین کند که آیا کاربر در حال انجام حرکت دیگری است - به ویژه، بزرگنمایی با دو ضربه. بدیهی است که در مواردی که می خواهید به لمس انگشت پاسخ آنی داشته باشید، این می تواند مشکل ساز باشد. تلاش برای محدود کردن سناریوهایی که در آن این تأخیر به طور خودکار اتفاق می‌افتد، در حال انجام است.

کروم برای اندروید مرورگر اندروید اپرا موبایل برای اندروید) فایرفاکس برای اندروید سافاری iOS
نمای غیر مقیاس پذیر بدون تاخیر 300 میلی‌ثانیه 300 میلی‌ثانیه بدون تاخیر 300 میلی‌ثانیه
بدون Viewport 300 میلی‌ثانیه 300 میلی‌ثانیه 300 میلی‌ثانیه 300 میلی‌ثانیه 300 میلی‌ثانیه

اولین و ساده ترین راه برای جلوگیری از این تاخیر این است که به مرورگر تلفن همراه بگویید که صفحه شما نیازی به بزرگنمایی ندارد - این کار را می توان با استفاده از یک 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> بپیچانید تا آن را به یک تبلت نیز تبدیل کنید - به این ترتیب کاربر می‌تواند اطلاعات اضافی را روی نشان دادن یا کلیک ماوس، ضربه زدن لمسی یا فشار کلید، بدون جاوا اسکریپت تغییر دهد. مورد نیاز است. وقتی شروع به کار کردم تا زمینه بازی صوتی وب خود را به خوبی با رابط های لمسی که منوهای بازشو من قبلاً روی لمس خوب کار می کردند، شروع کردم، شگفت زده شدم، زیرا من از این نوع ساختار استفاده کرده بودم!

روش فوق برای رابط های مبتنی بر اشاره گر ماوس و همچنین برای رابط های لمسی به خوبی کار می کند. این برخلاف استفاده از ویژگی‌های "عنوان" در شناور است، که وقتی عنصر فعال می‌شود نشان داده نمی‌شود:

<img src="/awesome.png" title="this doesn't show up in touch">

شماره 5: لمس در مقابل دقت ماوس

در حالی که موش‌ها از واقعیت جدایی مفهومی دارند، به نظر می‌رسد که بسیار دقیق هستند، زیرا سیستم عامل زیربنایی به طور کلی دقت پیکسل دقیق مکان‌نما را ردیابی می‌کند. از سوی دیگر، توسعه‌دهندگان موبایل یاد گرفته‌اند که لمس انگشت روی صفحه لمسی، بیشتر به دلیل اندازه سطح انگشت هنگام تماس با صفحه نمایش (و تا حدی به این دلیل که انگشتان شما مانع از نمایشگر می‌شوند) دقیق نیستند.

بسیاری از افراد و شرکت‌ها تحقیقات گسترده‌ای در مورد نحوه طراحی اپلیکیشن‌ها و سایت‌هایی انجام داده‌اند که تعامل مبتنی بر انگشت را در خود جای می‌دهند و کتاب‌های زیادی در این زمینه نوشته شده است. توصیه اصلی این است که اندازه اهداف لمسی را با افزایش بالشتک افزایش دهید و با افزایش حاشیه بین عناصر، احتمال ضربه های نادرست را کاهش دهید. (حاشیه‌ها در مدیریت تشخیص ضربه رویدادهای لمس و کلیک گنجانده نمی‌شوند، در حالی که padding است.) یکی از راه‌حل‌های اصلی که باید در Web Audio Playground انجام می‌دادم افزایش اندازه نقاط اتصال بود تا راحت‌تر لمس شوند. به طور دقیق

بسیاری از فروشندگان مرورگر که رابط‌های مبتنی بر لمس را مدیریت می‌کنند، منطق را به مرورگر وارد کرده‌اند تا به هدف قرار دادن عنصر صحیح زمانی که کاربر صفحه را لمس می‌کند و کاهش احتمال کلیک‌های نادرست کمک می‌کند - اگرچه این معمولا فقط رویدادهای کلیک را تصحیح می‌کند، نه حرکت را (اگرچه اینترنت اکسپلورر به نظر می رسد که رویدادهای ماوس کردن / جابجایی / موس را نیز تغییر می دهد).

شماره 6: کنترل کننده های لمسی را محدود نگه دارید، در غیر این صورت آنها اسکرول شما را خراب می کنند

همچنین مهم است که کنترل کننده های لمسی را فقط به عناصری که به آنها نیاز دارید محدود کنید. عناصر لمسی می‌توانند پهنای باند بسیار بالایی داشته باشند، بنابراین مهم است که از کنترل‌کننده‌های لمسی در عناصر پیمایش اجتناب کنید (زیرا پردازش شما ممکن است با بهینه‌سازی مرورگر برای پیمایش سریع لمسی بدون جانک تداخل داشته باشد - مرورگرهای مدرن سعی می‌کنند روی یک رشته GPU پیمایش کنند، اما این غیرممکن است. اگر آنها باید ابتدا با جاوا اسکریپت بررسی کنند تا ببینند آیا هر رویداد لمسی قرار است توسط برنامه مدیریت شود یا خیر. می توانید نمونه ای از این رفتار را بررسی کنید.

یکی از راهنمایی‌هایی که باید برای جلوگیری از این مشکل دنبال کنید این است که مطمئن شوید اگر فقط رویدادهای لمسی را در بخش کوچکی از رابط کاربری خود مدیریت می‌کنید، فقط کنترل‌کننده‌های لمسی را در آنجا وصل می‌کنید (نه، به عنوان مثال، در <body> صفحه) ; به طور خلاصه، دامنه کنترل کننده های لمسی خود را تا حد امکان محدود کنید.

شماره 7: چند لمسی

چالش جالب آخر این است که اگرچه ما از آن به عنوان رابط کاربری "لمس" یاد می‌کنیم، تقریباً در سراسر جهان پشتیبانی از Multi-touch است - یعنی APIها بیش از یک ورودی لمسی را در یک زمان ارائه می‌دهند. همانطور که شروع به پشتیبانی از لمس در برنامه های خود می کنید، باید در نظر بگیرید که چگونه لمس های متعدد ممکن است بر برنامه شما تأثیر بگذارد.

اگر در حال ساخت برنامه‌هایی بوده‌اید که عمدتاً توسط ماوس هدایت می‌شوند، پس عادت کرده‌اید که حداکثر با یک نقطه مکان‌نما بسازید - سیستم‌ها معمولاً از چندین نشانگر ماوس پشتیبانی نمی‌کنند. برای بسیاری از برنامه‌ها، شما فقط رویدادهای لمسی را به یک رابط مکان‌نما نگاشت می‌کنید، اما بیشتر سخت‌افزارهایی که برای ورودی لمسی دسک‌تاپ دیده‌ایم می‌توانند حداقل ۲ ورودی همزمان را مدیریت کنند، و به نظر می‌رسد اکثر سخت‌افزارهای جدید حداقل ۵ ورودی همزمان را پشتیبانی می‌کنند. . البته برای توسعه یک صفحه کلید پیانو روی صفحه ، باید بتوانید از چندین ورودی لمسی همزمان پشتیبانی کنید.

رابط‌های برنامه‌نویسی کاربردی W3C Touch که در حال حاضر پیاده‌سازی شده‌اند، هیچ API برای تعیین تعداد نقاط لمسی که سخت‌افزار پشتیبانی می‌کند، ندارند، بنابراین باید از بهترین تخمین خود برای تعداد نقاط لمسی که کاربران شما می‌خواهند استفاده کنید - یا، البته، به تعداد لمس‌ها نیز توجه کنید. نکاتی را که در عمل می بینید و تطبیق می دهید. به عنوان مثال، در یک برنامه پیانو، اگر هرگز بیش از دو نقطه لمسی نمی بینید، ممکن است بخواهید چند "آکورد" UI اضافه کنید. PointerEvents API یک API برای تعیین قابلیت های دستگاه دارد.

لمس کردن

امیدواریم این مقاله به شما راهنمایی هایی در مورد چالش های رایج در پیاده سازی لمس در کنار تعاملات ماوس داده باشد. البته مهمتر از هر توصیه دیگری این است که باید برنامه خود را روی موبایل، تبلت و محیط های دسکتاپ ترکیبی موس و لمسی تست کنید. اگر سخت‌افزار لمسی + ماوس ندارید، از " Emulate touch events " Chrome استفاده کنید تا به شما در آزمایش سناریوهای مختلف کمک کند.

ایجاد تجربیات تعاملی جذابی که همزمان با ورودی لمسی، ورودی ماوس و حتی هر دو سبک تعامل به خوبی کار می‌کنند، نه تنها ممکن است، بلکه نسبتاً آسان است، پیروی از این دستورالعمل‌ها.