اللمس والماوس

معًا للمرة الأولى

مقدمة

على مدى ما يقرب من ثلاثين عامًا، تمحورت تجارب الحوسبة المكتبية حول لوحة المفاتيح والماوس أو لوحة اللمس كأجهزة إدخال المستخدمين الرئيسية. لكن على مدار العقد الماضي، جلبت الهواتف الذكية والأجهزة اللوحية نموذجًا جديدًا للتفاعل: اللمس. مع طرح أجهزة Windows 8 التي تعمل باللمس، والآن مع إطلاق جهاز Chromebook Pixel الرائعة الذي يعمل باللمس، أصبح اللمس جزءًا من تجربة سطح المكتب المتوقعة. يتمثل أحد أكبر التحديات في بناء تجارب لا تعمل فقط على الأجهزة التي تعمل باللمس وأجهزة الماوس، ولكن أيضًا على هذه الأجهزة حيث سيستخدم المستخدم طريقتي الإدخال - أحيانًا في وقت واحد!

ستساعدك هذه المقالة على فهم كيفية دمج إمكانات اللمس في المتصفح، وكيف يمكن دمج هذه الآلية الجديدة للواجهة مع تطبيقاتك الحالية، وكيف يمكن أن يعمل اللمس بشكل جيد مع إدخالات الماوس.

حالة اللمس في منصة الويب

كان iPhone أول نظام أساسي شائع يحتوي على واجهات برمجة تطبيقات تعمل باللمس مخصصة في متصفح الويب. أنشأ العديد من مورِّدي المتصفِّحات الآخرين واجهات برمجة تطبيقات مشابهة تم إنشاؤها لتتوافق مع عملية تنفيذ نظام التشغيل iOS، والتي تم توضيحها الآن من خلال مواصفات"الإصدار 1 من أحداث اللمس". ويتم توفير أحداث اللمس في متصفّح Chrome وFirefox على أجهزة الكمبيوتر المكتبي وSafari على نظامَي التشغيل iOS وChrome ومتصفّح Android على أجهزة Android، بالإضافة إلى المتصفّحات الأخرى المتوافقة مع الأجهزة الجوّالة، مثل Blackberry.

لقد كتب زميلي "بوريس سموس" دليلاً تعليميًا رائعًا حول HTML5Rocks عن الأحداث التي تعمل باللمس، وهذا ما يجعلها طريقة جيدة للبدء في حال لم يسبق لك الاطّلاع على أحداث اللمس. في الواقع، إذا لم يسبق لك التعامل مع أحداث اللمس، فاقرأ هذه المقالة الآن قبل المتابعة. هيا، سأنتظر.

هل اكتملت العملية؟ والآن بعد أن تم أساسيات إنشاء الأحداث التي تعتمد على اللمس، يتمثّل التحدي في كتابة التفاعلات التي تعتمد على اللمس في أنّ تفاعلات اللمس يمكن أن تكون مختلفة بعض الشيء عن أحداث الماوس (ولوحة اللمس التي تعتمد على محاكاة الماوس وكرة التتبع)، وعلى الرغم من أنّ واجهات اللمس تحاول عادةً محاكاة الفئران، فإنّ هذه الطريقة ليست مثالية أو مكتملة. عليك العمل باستخدام أسلوبَي التفاعل، وقد تحتاج أيضًا إلى دعم كل واجهة بشكل مستقل.

الأهم من ذلك: قد يكون للمستخدم لمسة وفأر

أنشأ العديد من المطوّرين مواقع إلكترونية تكتشف بشكل ثابت ما إذا كانت البيئة تتيح أحداث اللمس، ثم يفترضون أنّهم بحاجة إلى إتاحة أحداث اللمس (وليس الماوس) فقط. أصبح هذا الافتراض غير صحيح، ولكن لا يعني توفُّر أحداث باللمس أنّ المستخدِم يستخدم بشكل أساسي جهاز الإدخال الذي يعمل باللمس. أصبحت الأجهزة مثل Chromebook Pixel وبعض أجهزة الكمبيوتر المحمولة التي تعمل بنظام التشغيل Windows 8 متوافقة الآن مع طريقتي الإدخال باللمس والماوس، وستكون المزيد من الأجهزة متوافقة في المستقبل القريب. في هذه الأجهزة، من الطبيعي جدًا أن يستخدم المستخدمون كلاً من الماوس وشاشة اللمس للتفاعل مع التطبيقات، لذلك فإن ميزة "دعم اللمس" ليست هي نفسها عبارة "لا تحتاج إلى دعم بالماوس". لا يمكنك التفكير في المشكلة على أنها "يجب أن أكتب نمطين مختلفين للتفاعل والتبديل بينهما"، فأنت بحاجة إلى التفكير في كيفية عمل كلا التفاعلين معًا وكذلك بشكل مستقل. على جهاز Chromebook Pixel، أستخدم لوحة اللمس بشكل متكرر، لكنني أيضًا أصلم إلى الشاشة ويلمسها - على نفس التطبيق أو الصفحة، أقوم بأي شيء يبدو طبيعيًا في الوقت الحالي. ومن ناحية أخرى، نادرًا ما يستخدم بعض مستخدمي أجهزة الكمبيوتر المحمول ذات الشاشات التي تعمل باللمس الشاشة التي تعمل باللمس إذا سبق لهم استخدام الشاشة التي تعمل باللمس، وبالتالي يجب ألا يؤدي استخدام الإدخال باللمس إلى إيقاف التحكّم بالماوس أو إعاقة استخدامه.

قد يصعُب معرفة ما إذا كانت بيئة متصفّح المستخدم تتيح الإدخال باللمس أم لا. ومن الأفضل أن يشير المتصفّح على جهاز سطح المكتب دائمًا إلى توافقه مع أحداث اللمس حتى يمكن توصيل شاشة تعمل باللمس في أي وقت (على سبيل المثال، إذا أصبحت شاشة تعمل باللمس متصلة من خلال KVM متاحة). مع كل هذه الأسباب، من المفترض ألا تحاول تطبيقاتك التبديل بين اللمس والماوس، بل تدعم كليهما.

إتاحة استخدام الماوس واللمس معًا

1 - النقر والنقر - ترتيب الأشياء "الطبيعي"

المشكلة الأولى هي أن واجهات اللمس تحاول عادةً محاكاة نقرات الماوس، وهذا واضح، لأن واجهات اللمس تحتاج إلى العمل على التطبيقات التي لم تتفاعل من قبل إلا مع أحداث الماوس! يمكنك استخدام هذا الاختصار، لأنّ أحداث "النقر" سيستمر تنشيطها، سواء نقر المستخدم بالماوس أو نقر بالإصبع على الشاشة. مع ذلك، هناك مشكلتان في هذا الاختصار.

أولاً، يجب توخي الحذر عند تصميم تفاعلات اللمس الأكثر تقدمًا: عندما يستخدم المستخدم الماوس، سيستجيب عن طريق حدث النقر، ولكن عندما يلمس المستخدم الشاشة سيحدث كل من حدثَي اللمس والنقر. بنقرة واحدة، يكون ترتيب الأحداث هو:

  1. بدء اللمس
  2. تحريك باللمس
  3. نقطة لمس
  4. تمرير الماوس
  5. mousemove
  6. تمرير الماوس للأسفل
  7. تحريك الماوس
  8. نقرة

وهذا يعني بالطبع أنّه إذا كنت تعالج أحداث اللمس، مثل البدء باللمس، عليك التأكّد من عدم معالجة حدث النقر و/أو تحريك الماوس المقابل للأسفل أيضًا. إذا كان بإمكانك إلغاء أحداث اللمس (استدعاء preventDefault() داخل معالج الأحداث)، لن يتم إنشاء أي أحداث للماوس باللمس. إحدى أهم قواعد معالِجات اللمس هي:

مع ذلك، يمنع ذلك أيضًا السلوك التلقائي الآخر للمتصفِّح (مثل التمرير)، علمًا أنّك تتعامل عادةً مع حدث اللمس بشكل كامل في المعالج، وتريد إيقاف الإجراءات التلقائية. بشكل عام، قد تحتاج إلى معالجة جميع أحداث اللمس وإلغائها أو تجنب توفُّر معالج لهذا الحدث.

ثانيًا، عندما ينقر المستخدم على عنصر في صفحة ويب على جهاز جوّال، يكون هناك تأخير في الصفحات التي لم يتم تصميمها للتفاعل مع الأجهزة الجوّالة لمدة لا تقل عن 300 مللي ثانية بين حدث البدء باللمس ومعالجة أحداث الماوس (الماوس). يمكن إجراء ذلك باستخدام Chrome، ويمكنك تفعيل "محاكاة أحداث اللمس" في "أدوات مطوّري برامج Chrome" لمساعدتك في اختبار واجهات اللمس على نظام لا يعمل باللمس.

ويمنح هذا التأخير المتصفِّح وقتًا لتحديد ما إذا كان المستخدم يؤدي إيماءة أخرى، وخاصةً النقر مرّتين للتكبير أو التصغير. ومن الواضح أن هذا قد يكون مشكلة في الحالات التي تريد فيها الاستجابة الفورية لمسة إصبع. ثمّة أعمال متواصلة لمحاولة الحدّ من حالات حدوث هذا التأخير تلقائيًا.

Chrome لنظام Android متصفح Android Opera Mobile لنظام التشغيل Android) Firefox لنظام Android Safari لنظام التشغيل iOS
إطار عرض غير قابل للتوسع بلا تأخير 300 ملي ثانية 300 ملي ثانية بلا تأخير 300 ملي ثانية
ما مِن إطار عرض 300 ملي ثانية 300 ملي ثانية 300 ملي ثانية 300 ملي ثانية 300 ملي ثانية

الطريقة الأولى والأسهل لتجنب هذا التأخير هي "إعلام" متصفح الجوّال بأن صفحتك لن تحتاج إلى تكبير، ويمكن إجراء ذلك باستخدام إطار عرض ثابت، على سبيل المثال عن طريق الإدراج في صفحتك:

<meta name="viewport" content="width=device-width,user-scalable=no">

بالطبع، لا يكون هذا الإجراء مناسبًا في بعض الأحيان، لأنّ هذا يؤدي إلى إيقاف التكبير أو التصغير بإصبعين، وقد يكون هذا الإجراء مطلوبًا لأسباب تتعلّق بإمكانية الوصول، لذا استخدمه باعتدال إذا عطّلتَ خاصية تغيير حجم المستخدم، فقد تحتاج إلى توفير طريقة أخرى لزيادة قابلية قراءة النص في تطبيقك. وينطبق ذلك أيضًا على متصفِّح Chrome على أجهزة كمبيوتر سطح المكتب التي تتيح لمس الجهاز، والمتصفحات الأخرى على الأنظمة الأساسية للأجهزة الجوّالة عندما تحتوي الصفحة على إطارات عرض غير قابلة للتوسّع، لا ينطبق هذا التأخير.

2: أحداث Mousemove لا يتم تنشيطها باللمس

من المهم الإشارة في هذه المرحلة إلى أنّ محاكاة أحداث الماوس في أي واجهة تعمل باللمس لا يمتد عادةً إلى محاكاة أحداث تحريك الماوس، لذلك إذا أنشأت عنصر تحكُّم رائعًا يعمل بالماوس ويستخدم أحداث تحريك الماوس، لن يعمل على الأرجح مع أي جهاز يعمل باللمس ما لم تُضِف على وجه التحديد معالِجات حركات الماوس.

تنفِّذ المتصفحات عادةً التفاعل المناسب لتفاعلات اللمس تلقائيًا على عناصر تحكم HTML، وبالتالي، على سبيل المثال، ستعمل عناصر التحكّم في نطاق HTML5 فقط عند استخدام تفاعلات اللمس. مع ذلك، إذا كنت قد نفذت عناصر التحكم الخاصة بك، فلن تعمل على الأرجح على تفاعلات النقر والسحب. في الواقع، بعض المكتبات الشائعة الاستخدام (مثل jQueryUI) لا تتيح بعد تفاعلات اللمس بهذه الطريقة في الأصل (على الرغم من ذلك، بالنسبة إلى jQueryUI، هناك العديد من إصلاحات الأخطاء لهذه المشكلة). كانت هذه إحدى المشاكل الأولى التي واجهتها عند ترقية تطبيق Web Audio Playground للعمل باللمس، حيث كانت أشرطة التمرير تعتمد على jQueryUI، لذا لم تكن تعمل مع تفاعلات النقر والسحب. ثم انتقلت إلى عناصر التحكم في نطاق HTML5، ونجحت في ذلك. بدلاً من ذلك، يمكنني ببساطة إضافة معالِجات حركة اللمس لتعديل أشرطة التمرير، ولكن هناك مشكلة واحدة في ذلك...

3: Touchmove وMouseMove ليسا نفس الشيء

أحد الأخطاء التي يقع فيها بعض مطوّري البرامج هو أنّ معالِجات تحريك الماوس وحركة اللمس تطلب الوصول إلى مسارات الترميز نفسها. سلوك هذه الأحداث قريب جدًا، لكنّه مختلف عنها بشكلٍ طفيف، وبالأخص تستهدِف أحداث اللمس دائمًا العنصر الذي لمسته "تم البدء"، في حين تستهدِف أحداث الماوس العنصر الحالي أسفل مؤشر الماوس. ولهذا السبب، لدينا أحداث تمرير الماوس وتمرير الماوس، ولكن لا تتوفّر أحداث تمرير الماوس ولمساته المقابلة - فقط نقاط اللمس.

الطريقة الأكثر شيوعًا التي يمكن أن يلدعك بها هذا الأمر هي إزالة (أو نقل) العنصر الذي بدأ المستخدم في لمسه. على سبيل المثال، يمكنك إنشاء لوحة عرض دوّارة للصور مع معالِج لمس على لوحة العرض الدوّارة بالكامل لدعم سلوك التمرير المخصّص. ومع تغيُّر الصور المتاحة، تتم إزالة بعض عناصر <img> وإضافة عناصر أخرى. إذا تصادف أن بدأ المستخدم لمس إحدى هذه الصور ثم أزلتها، فإن المعالج (المتوفر على أصل عنصر الصورة) سيتوقف فقط عن تلقي أحداث اللمس (لأنه يتم توجيهه إلى هدف لم يعد في الشجرة)، وسيبدو الأمر وكأن المستخدم يمسك بإصبعه في مكان واحد بالرغم من نقله وإزالته في النهاية.

يمكنك بالطبع تجنُّب هذه المشكلة من خلال تجنُّب إزالة العناصر التي تحتوي على معالجات لمس (أو تحتوي على أسلاف لها) عندما يكون اللمس نشطًا. بدلاً من ذلك، ننصح بتسجيل المعالِجات الثابتة للبداية أو اللمس، بدلاً من تسجيل معالِجات اللمس الثابتة، ثمّ الانتظار إلى أن يظهر حدث البدء باللمس، ثم إضافة معالِجات Touchmove/Touchend/Touchcancel إلى target في حدث بدء اللمس (وإزالتها عند الانتهاء أو الإلغاء). بهذه الطريقة، سيظل بإمكانك تلقّي أحداث عند اللمس حتى إذا تم نقل العنصر الهدف أو إزالته. يمكنك تجربة هذه اللعبة قليلاً هنا - المس المربع الأحمر مع الاستمرار في الضغط على مفتاح Escape لإزالته من DOM.

رقم 4: اللمس والتمرير

فصلت استعارة مؤشر الماوس موضع المؤشر عن التحديد النشط، وأتاح ذلك للمطوّرين استخدام حالات التمرير لإخفاء المعلومات التي قد تكون ذات صلة بالمستخدمين وعرضها. مع ذلك، لا ترصد معظم واجهات اللمس في الوقت الحالي إصبعًا "يتحرك" فوق هدف، وبالتالي فإنّ توفير معلومات مهمة دلاليًا (على سبيل المثال، من خلال عرض نافذة منبثقة "ما هو عنصر التحكّم هذا؟") استنادًا إلى التمرير هو أمر لا يعتبر قبولاً، ما لم توفّر أيضًا طريقة سهلة للوصول إلى هذه المعلومات عن طريق اللمس. يجب أن تكون حذرًا بشأن كيفية استخدام التمرير لنقل المعلومات إلى المستخدمين.

ومن المثير للاهتمام، على الرغم من ذلك، يمكن أن يتم تشغيل الفئة CSS :hover pseudoclass من خلال واجهات تعمل باللمس في بعض الحالات، ويؤدي النقر على أحد العناصر إلى جعله نشطًا بينما يكون الإصبع لأسفل، كما يؤدي النقر عليه إلى الحصول على حالة :hover. (في المتصفح Internet Explorer، لا يسري تأثير التمرير: إلا أثناء وجود إصبع المستخدم لأسفل - وتحافظ المتصفحات الأخرى على استمرار تأثير التمرير حتى النقر أو الماوس التالي.) هذه طريقة جيدة لجعل القوائم المنبثقة تعمل على واجهات اللمس - من الآثار الجانبية لتنشيط العنصر تطبيق حالة :التمرير أيضًا. مثلاً:

<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> لجعله علامة جدولة أيضًا، وبذلك يمكن للمستخدم تبديل المعلومات الإضافية من خلال التمرير بالماوس أو النقر، أو النقر باللمس، أو الضغط على مفتاح، بدون الحاجة إلى JavaScript. تفاجأت عندما بدأت العمل على إنشاء Web Audio Playground ليعمل بشكل جيد مع واجهات اللمس التي عملت بها القوائم المنبثقة بشكل جيد عند لمسها، لأنّني استخدمت هذا النوع من البنية.

تعمل الطريقة أعلاه بشكل جيد مع الواجهات التي تعتمد على مؤشر الماوس، وكذلك مع الواجهات التي تعمل باللمس. ويختلف ذلك عن استخدام سمات "title" (العنوان) عند التمرير فوقها، والتي لن تظهر عند تفعيل العنصر:

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

رقم 5: دقة اللمس مقابل دقة الماوس

في حين أن الفئران لديها انفصال نظري عن الواقع، اتضح أنها دقيقة للغاية، حيث يتتبع نظام التشغيل الأساسي بشكل عام دقة البكسل الدقيقة للمؤشر. من ناحية أخرى، أدرك مطوّرو الهواتف الجوّالة أنّ اللمسات بالأصابع على شاشة تعمل باللمس ليست دقيقة، ويرجع هذا في الغالب إلى حجم مساحة سطح الإصبع عند ملامسة الشاشة (وجزئيًا لأنّ أصابعك تحجب الشاشة).

لقد أجرى العديد من الأفراد والشركات أبحاثًا مكثفة في سلوكيات المستخدمين حول كيفية تصميم تطبيقات ومواقع يسهل التفاعل من خلال الإصبع، كما تمت كتابة العديد من الكتب حول هذا الموضوع. النصيحة الأساسية هي زيادة حجم مساحات اللمس عن طريق زيادة المساحة المتروكة وتقليل احتمالية النقر غير الصحيح عن طريق زيادة الهامش بين العناصر. (لا يتم تضمين الهوامش في معالجة اكتشاف النتائج لأحداث اللمس والنقر، في حين أن المساحة المتروكة هي المتروكة). كان أحد الإصلاحات الأساسية التي كان عليّ إجراؤها في Web Audio Playground هو زيادة أحجام نقاط الاتصال بحيث يمكن لمسها بدقة أكبر.

لقد قدّم العديد من مورّدي المتصفحات الذين يتعاملون مع الواجهات التي تعتمد على اللمس منطقًا في المتصفح للمساعدة في استهداف العنصر الصحيح عندما يلمس المستخدم الشاشة وتقليل احتمالية حدوث نقرات غير صحيحة، على الرغم من أن هذا الإجراء عادةً ما يصحح فقط أحداث النقر ولا يتحرك إلا (على الرغم من أن Internet Explorer يبدو أنه يمكنه تعديل أحداث الماوس لأسفل/نقل الماوس/الماوس أيضًا).

الطريقة رقم 6: تضمين معالِجات اللمس باستمرار، وإلا سينتج عن ذلك

من المهم أيضًا حصر معالِجات اللمس بالعناصر التي تحتاج إليها فقط، لأنّ عناصر اللمس يمكن أن تكون معدّل نقل بيانات عاليًا جدًا، لذلك من المهم تجنُّب معالِجات اللمس على عناصر التمرير (لأنّ المعالجة التي تُجريها قد تتداخل مع تحسينات المتصفّح للتمرير السريع بدون عرض باللمس). يمكنك الاطّلاع على مثال لهذا السلوك.

لتجنُّب هذه المشكلة، عليك التأكّد من تضمين معالِجات اللمس فيها فقط في جزء صغير من واجهة المستخدم (وليس على <body> مثلاً من الصفحة مثلاً). باختصار، يمكنك حصر نطاق معالِجات اللمس بقدر الإمكان.

7: اللمس المتعدد

التحدي الأخير المثير للاهتمام هو أنّه على الرغم من أنّنا نشير إلى هذه الواجهة على أنّها واجهة مستخدم "اللمس"، تتوفَّر ميزة "اللمس المتعدد" في جميع أنحاء العالم تقريبًا، أي أنّ واجهات برمجة التطبيقات توفّر أكثر من إدخال لمس واحد في الوقت نفسه. عندما تبدأ في دعم اللمس في تطبيقاتك، يجب أن تفكر في كيفية تأثير اللمسات المتعددة على تطبيقك.

إذا كنت تنشئ تطبيقات تعمل بالماوس في الأساس، فأنت معتاد على إنشاء تطبيقات باستخدام نقطة مؤشر واحدة على الأكثر، حيث لا تتوافق الأنظمة عادةً مع مؤشرات ماوس متعددة. بالنسبة إلى العديد من التطبيقات، سيكون عليك ربط أحداث اللمس بواجهة مؤشر واحدة فقط، إلا أنّ معظم أجهزة الإدخال باللمس على سطح المكتب يمكنها التعامل مع إدخالَين متزامنَين على الأقل، ويبدو أنّ معظم الأجهزة الجديدة تتيح 5 إدخالات متزامنة على الأقل. لتطوير لوحة مفاتيح بيانو على الشاشة، قد تحتاج بالطبع إلى دعم عدة إدخالات لمس متزامنة.

لا تحتوي واجهات برمجة تطبيقات W3C Touch التي تم تنفيذها حاليًا على واجهة برمجة تطبيقات لتحديد عدد نقاط الاتصال التي يدعمها الجهاز، لذا عليك استخدام أفضل تقدير لديك لعدد نقاط الاتصال التي سيحتاجها المستخدمون، أو بالطبع، عليك الانتباه إلى عدد نقاط الاتصال التي تراها عمليًا والتكيف. على سبيل المثال، في تطبيق البيانو، إذا لم يظهر لك أبدًا أكثر من نقطتَي اتصال، فقد تحتاج إلى إضافة بعض واجهة مستخدم "الأوتار". تتضمن واجهة برمجة التطبيقات PointerEvents API واجهة برمجة تطبيقات لتحديد إمكانات الجهاز.

اللمسات الأخيرة

نأمل أن تكون هذه المقالة قد قدّمت لك بعض الإرشادات حول التحديات الشائعة في تنفيذ تفاعلات اللمس إلى جانب تفاعلات الماوس. والأهم من أي نصيحة أخرى، بالطبع، هو أنك تحتاج إلى اختبار تطبيقك على بيئات الهاتف المحمول والأجهزة اللوحية وبيئات سطح المكتب المشتركة للماوس واللمس. إذا لم يكن لديك جهاز يعمل باللمس أو الماوس، يمكنك استخدام ميزة "محاكاة أحداث اللمس" في Chrome لمساعدتك في اختبار السيناريوهات المختلفة.

لا تقتصر تجربة هذه الإرشادات على إمكانية إنشاء تجارب تفاعلية تفاعلية بشكل جيد باستخدام الإدخال باللمس وإدخال الماوس، فضلاً عن أنّه من السهل نسبيًا اتّباع هذه الإرشادات.