معًا للمرة الأولى
مقدمة
على مدار ما يقرب من ثلاثين عامًا، كانت تجارب استخدام أجهزة الكمبيوتر المكتبي تركّز على لوحة المفاتيح والماوس أو لوحة اللمس كأداة إدخال رئيسية للمستخدم. ومع ذلك، خلال العقد الماضي، وفّرت الهواتف الذكية والأجهزة اللوحية نموذج تفاعل جديدًا: اللمس. مع طرح أجهزة Windows 8 المزوّدة بشاشة تعمل باللمس، والآن مع إصدار جهاز Chromebook Pixel الرائع المزوّد بشاشة تعمل باللمس، أصبحت شاشة اللمس جزءًا من تجربة سطح المكتب المتوقّعة. يتمثل أحد أكبر التحديات في إنشاء تجارب لا تعمل فقط على الأجهزة التي تعمل باللمس وأجهزة الماوس، بل أيضًا على هذه الأجهزة التي سيستخدم فيها المستخدم طريقتَي الإدخال معًا، أحيانًا في الوقت نفسه.
ستساعدك هذه المقالة في فهم كيفية دمج إمكانات اللمس في المتصفّح، وكيفية دمج آلية الواجهة الجديدة هذه في تطبيقاتك الحالية، وكيفية استخدام إمكانات اللمس مع إدخال الماوس.
حالة اللمس في منصة الويب
كان هاتف iPhone أول منصة رائجة تتضمّن واجهات برمجة تطبيقات مخصّصة للأجهزة التي تعمل باللمس ومضمّنة في متصفّح الويب. أنشأ العديد من مورّدي المتصفّحات الآخرين واجهات واجهة برمجة تطبيقات مشابهة تم إنشاؤها لتتوافق مع تنفيذ iOS، والذي يُوضّح الآن من خلال مواصفة"أحداث اللمس، الإصدار 1". تتوفّر أحداث اللمس في Chrome وFirefox على أجهزة الكمبيوتر المكتبي، وSafari على أجهزة iOS وChrome ومتصفّح Android على أجهزة Android، بالإضافة إلى متصفّحات الأجهزة الجوّالة الأخرى مثل متصفّح Blackberry.
كتب زميلي "بوريس سموس" دليلاً تعليميًا رائعًا على HTML5Rocks حول أحداث اللمس لا يزال يشكّل طريقة جيدة للبدء إذا لم يسبق لك الاطّلاع على أحداث اللمس. في الواقع، إذا لم يسبق لك التعامل مع أحداث اللمس، ننصحك بقراءة هذه المقالة الآن قبل المتابعة. يُرجى المتابعة، وسننتظرك.
هل اكتملت العملية؟ والآن بعد أن تم أساسيات إنشاء الأحداث التي تعتمد على اللمس، يتمثّل التحدي في كتابة التفاعلات التي تعتمد على اللمس في أنّ تفاعلات اللمس يمكن أن تكون مختلفة بعض الشيء عن أحداث الماوس (ولوحة اللمس التي تعتمد على محاكاة الماوس وكرة التتبع)، وعلى الرغم من أنّ واجهات اللمس تحاول عادةً محاكاة الفئران، فإنّ هذه الطريقة ليست مثالية أو مكتملة. عليك العمل باستخدام أسلوبَي التفاعل، وقد تحتاج أيضًا إلى دعم كل واجهة بشكل مستقل.
الأهم من ذلك: قد يمتلك المستخدم جهاز لمس وماوسًا.
أنشأ العديد من المطوّرين مواقع إلكترونية ترصد بشكلٍ ثابت ما إذا كانت البيئة تتيح أحداث اللمس، ثم تفترض أنّها تحتاج فقط إلى السماح بأحداث اللمس (وليس أحداث الماوس). هذا الافتراض غير صحيح الآن، فمجرد توفّر أحداث اللمس لا يعني أنّ المستخدم يستخدم جهاز الإدخال باللمس هذا بشكل أساسي. تتيح الآن أجهزة مثل Chromebook Pixel وبعض أجهزة الكمبيوتر المحمول التي تعمل بنظام التشغيل Windows 8 استخدام كل من أسلوبَي الإدخال باللمس والماوس، وستتوفّر هذه الميزة في المزيد من الأجهزة في المستقبل القريب. في هذه الأجهزة، من الطبيعي جدًا أن يستخدم المستخدمون كلاً من الماوس وشاشة اللمس للتفاعل مع التطبيقات، لذلك فإن ميزة "دعم اللمس" ليست هي نفسها عبارة "لا تحتاج إلى دعم بالماوس". لا يمكنك التفكير في المشكلة على أنّها "عليّ كتابة أسلوبَين مختلفَين للتفاعل والتبديل بينهما"، بل عليك التفكير في كيفية عمل التفاعلَين معًا بشكل مستقل. على جهاز Chromebook Pixel، أستخدم لوحة اللمس بشكل متكرّر، ولكنني ألمس الشاشة أيضًا. في التطبيق أو الصفحة نفسها، أفعل ما أراه مناسبًا في الوقت الحالي. من ناحية أخرى، نادرًا ما يستخدم بعض مستخدمي أجهزة الكمبيوتر المحمول التي تعمل باللمس شاشة اللمس، لذا يجب ألا يؤدي توفُّر ميزة الإدخال باللمس إلى إيقاف إمكانية التحكّم باستخدام الماوس أو إعاقتها.
قد يكون من الصعب معرفة ما إذا كانت بيئة المتصفّح لدى المستخدم تتيح الإدخال باللمس أم لا. من المفترض أن يشير المتصفّح على جهاز الكمبيوتر المكتبي دائمًا إلى توفّر أحداث اللمس حتى يمكن ربط شاشة لمس في أي وقت (على سبيل المثال، إذا أصبحت شاشة لمس متاحة من خلال وحدة التحكّم في الفيديو (KVM)). مع كل هذه الأسباب، من المفترض ألا تحاول تطبيقاتك التبديل بين اللمس والماوس، بل تدعم كليهما.
إتاحة الماوس واللمس معًا
#1 - النقر والضغط: الترتيب "الطبيعي" للأشياء
المشكلة الأولى هي أن واجهات اللمس تحاول عادةً محاكاة نقرات الماوس، وهذا واضح، لأن واجهات اللمس تحتاج إلى العمل على التطبيقات التي لم تتفاعل من قبل سوى مع أحداث الماوس! يمكنك استخدام هذا الإجراء كاختصار، لأنّه سيستمر تشغيل أحداث "النقر"، سواء نقر المستخدم باستخدام الماوس أو نقر إصبعه على الشاشة. ومع ذلك، هناك بعض المشاكل في هذا الاختصار.
أولاً، عليك الانتباه عند تصميم تفاعلات لمس أكثر تقدمًا: عندما يستخدم المستخدم الماوس، ستستجيب الشاشة من خلال حدث النقر، ولكن عندما يلمس المستخدم الشاشة، سيحدث كل من حدثَي اللمس والنقر. عند النقر مرة واحدة، يكون ترتيب الأحداث على النحو التالي:
- touchstart
- touchmove
- touchend
- تمرير الماوس
- mousemove
- mousedown
- mouseup
- نقرة
وهذا يعني بالطبع أنّه إذا كنت تعالج أحداث اللمس، مثل البدء باللمس، عليك التأكّد من عدم معالجة حدث النقر و/أو تحريك الماوس المقابل للأسفل أيضًا. إذا كان بإمكانك إلغاء أحداث اللمس (استدعاء preventDefault() داخل معالِج الحدث)، لن يتم إنشاء أي أحداث للماوس لللمس. من أهم قواعد معالجات اللمس:
ومع ذلك، يمنع هذا الإجراء أيضًا سلوك المتصفح التلقائي الآخر (مثل الانتقال للأعلى أو للأسفل) - على الرغم من أنّك عادةً ما تتعامل مع حدث اللمس بالكامل في معالِج الأحداث، وستحتاج إلى إيقاف الإجراءات التلقائية. بشكل عام، ستحتاج إلى معالجة جميع أحداث اللمس وإلغائها، أو تجنُّب استخدام معالِج لهذا الحدث.
ثانيًا، عندما ينقر المستخدم على عنصر في صفحة ويب على جهاز جوّال، يكون هناك تأخير في الصفحات التي لم يتم تصميمها للتفاعل مع الأجهزة الجوّالة لمدة لا تقل عن 300 مللي ثانية بين حدث بدء اللمس ومعالجة أحداث الماوس (الماوس). يمكن إجراء ذلك باستخدام Chrome، ويمكنك تفعيل "محاكاة أحداث اللمس" في أدوات مطوّري برامج Chrome لمساعدتك في اختبار الواجهات التي تعمل باللمس على نظام غير مزوّد بشاشة تعمل باللمس.
ويساعد هذا التأخير في منح المتصفّح وقتًا لتحديد ما إذا كان المستخدم يؤدي إيماءة أخرى، وخاصةً النقر مرّتين للتكبير أو التصغير. من الواضح أنّ هذا يمكن أن يشكّل مشكلة في الحالات التي تريد فيها الحصول على استجابة فورية عند لمس الشاشة. نحن نعمل على حلّ هذه المشكلة لمحاولة الحدّ من السيناريوهات التي يحدث فيها هذا التأخير تلقائيًا.
الطريقة الأولى والأسهل لتجنُّب هذا التأخير هي "إخبار" متصفّح الأجهزة الجوّالة بأنّ صفحتك لن تحتاج إلى تكبير/تصغير، ويمكن إجراء ذلك باستخدام إطار عرض ثابت، مثلاً عن طريق إدراج ما يلي في صفحتك:
<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 ليسا الأمر نفسه
من الأخطاء التي لاحظنا أنّ بعض المطوّرين يقعون فيها هي أنّ معالجَي touchmove وmousemove يُجريان استدعاءً إلى مسارات الرموز البرمجية نفسها. سلوك هذه الأحداث قريب جدًا، لكنّه مختلف عنها بشكلٍ طفيف، وبالأخص تستهدِف أحداث اللمس دائمًا العنصر الذي لمسته "تم البدء" فيه، في حين تستهدِف أحداث الماوس العنصر الحالي أسفل مؤشر الماوس. لهذا السبب، لدينا حدثَا mouseover وmouseout، ولكن لا يتوفّر حدثَا touchover وtouchout مقابلَين، بل يتوفّر حدث touchend فقط.
الطريقة الأكثر شيوعًا التي يمكن أن يلدعك بها هذا الأمر هي إزالة (أو نقل) العنصر الذي بدأ المستخدم في لمسه. على سبيل المثال، تخيل منصّة عرض بعناصر متغيّرة للصور تتضمّن معالِج لمس على منصّة العرض بأكملها لتتوافق مع سلوك التمرير المخصّص. عندما تتغيّر الصور المتاحة، يمكنك إزالة بعض عناصر <img>
وإضافة عناصر أخرى. إذا بدأ المستخدم باللمس على إحدى هذه الصور ثم أزلت العنصر، سيتوقف معالِج الأحداث (الذي يقع على أحد العناصر السابقة لعنصر img) عن تلقّي أحداث اللمس (لأنّه يتم إرساله إلى هدف لم يعُد في الشجرة)، وسيبدو أنّ المستخدم يضع إصبعه في مكان واحد على الرغم من أنّه قد ينقل إصبعه ويزيله في النهاية.
يمكنك بالطبع تجنُّب هذه المشكلة عن طريق تجنُّب إزالة العناصر التي تحتوي على معالِجات لمس (أو تحتوي على عناصر أصلية تحتوي على معالِجات لمس) عندما تكون لمسة نشطة. بدلاً من ذلك، ننصحك بالانتظار إلى أن تتلقّى حدث touchstart ثم إضافة معالجات touchmove/touchend/touchcancel إلى الهدف لحدث touchstart (وإزالتها عند انتهاء/إلغاء الحدث)، بدلاً من تسجيل معالجات touchend/touchmove الثابتة. بهذه الطريقة، سيظل بإمكانك تلقّي أحداث عند اللمس حتى إذا تم نقل العنصر الهدف أو إزالته. يمكنك تجربة هذا الأمر قليلاً هنا - يمكنك النقر على المربّع الأحمر مع الضغط على مفتاح Escape لإزالته من واجهة DOM.
#4: النقر والتأرجح
وقد فصلت استعارة مؤشر الماوس موضع المؤشر عن الاختيار النشط، ما سمح للمطوّرين باستخدام حالات التمرير لإخفاء المعلومات التي قد تكون ذات صلة بالمستخدمين وعرضها. مع ذلك، لا ترصد معظم واجهات اللمس في الوقت الحالي إصبعًا "يتحرك" فوق هدف، وبالتالي فإنّ توفير معلومات مهمة دلاليًا (على سبيل المثال، من خلال عرض نافذة منبثقة "ما هو عنصر التحكّم هذا؟") استنادًا إلى التمرير هو أمر لا يمكن استخدامه، ما لم توفّر أيضًا طريقة سهلة للوصول إلى هذه المعلومات عن طريق اللمس. يجب أن تكون حذرًا بشأن كيفية استخدامك للمرور مؤقتًا فوق العنصر من أجل نقل المعلومات إلى المستخدمين.
ومن المثير للاهتمام، على الرغم من ذلك، يمكن أن يتم تشغيل الفئة CSS :hover pseudoclass من خلال واجهات تعمل باللمس في بعض الحالات، ويؤدي النقر على أحد العناصر إلى جعله نشطًا بينما يكون الإصبع لأسفل، كما يؤدي النقر عليه إلى الحصول على حالة :hover. (في Internet Explorer، لا يكون التأثير :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>
لجعله علامة جدولة أيضًا، وبذلك يمكن للمستخدم نقل المعلومات الإضافية من خلال التمرير بالماوس أو النقر عليه أو الضغط عليه باللمس أو الضغط على مفتاح بدون الحاجة إلى JavaScript. لقد فاجأني أنّ القوائم المنبثقة في Web Audio Playground تعمل بشكل جيد على اللمس، وذلك لأنّني استخدمت هذا النوع من البنية عندما بدأت العمل على تحسين أداء هذه القوائم مع الواجهات التي تعمل باللمس.
تعمل الطريقة أعلاه بشكل جيد مع الواجهات المستندة إلى مؤشر الماوس، بالإضافة إلى الواجهات التي تعمل باللمس. يختلف ذلك عن استخدام سمات "العنوان" عند التمرير فوقها، والتي لن تظهر عند تفعيل العنصر:
<img src="/awesome.png" title="this doesn't show up in touch">
#5: دقة اللمس مقارنةً بدقة الماوس
على الرغم من انفصال الفئران عن الواقع، اتضح أنها دقيقة للغاية، حيث يتتبع نظام التشغيل الأساسي بشكل عام دقة البكسل الدقيقة للمؤشر. من ناحية أخرى، تبيّن لمطوّري التطبيقات المتوافقة مع الأجهزة الجوّالة أنّ لمسات الأصابع على الشاشة اللمسية ليست دقيقة بقدر كبير، ويعود ذلك في الغالب إلى حجم سطح الإصبع عند ملامستها للشاشة (وجزئيًا لأنّ أصابعك تحجب الشاشة).
لقد أجرى العديد من الأفراد والشركات أبحاثًا مكثفة في سلوكيات المستخدمين حول كيفية تصميم تطبيقات ومواقع يسهل التفاعل من خلال الإصبع، كما تمت كتابة العديد من الكتب حول هذا الموضوع. النصيحة الأساسية هي زيادة حجم أهداف اللمس من خلال زيادة الحشو، وتقليل احتمالية النقرات غير الصحيحة من خلال زيادة الهامش بين العناصر. (لا يتم تضمين الهوامش في عملية رصد النتائج لأحداث اللمس والنقر، ولكن يتم تضمين الحشو). كان أحد الإصلاحات الأساسية التي أجريتها على Web Audio Playground هو زيادة أحجام نقاط الربط لتسهيل لمسها بدقة.
وقد أدخل العديد من مورّدي المتصفّحات الذين يتعاملون مع الواجهات المستندة إلى اللمس منطقًا في المتصفّح للمساعدة في استهداف العنصر الصحيح عندما يلمس المستخدم الشاشة والحدّ من احتمالية حدوث نقرات غير صحيحة، على الرغم من أنّ هذا عادةً ما يؤدي إلى تصحيح أحداث النقر فقط وليس الأحداث المتعلّقة بالتنقّل (على الرغم من أنّه يبدو أنّ Internet Explorer يعدّل أحداث mousedown/mousemove/mouseup أيضًا).
#6: يجب إبقاء عناصر معالجة اللمس محصورة في نطاقها، وإلا ستؤدي إلى حدوث تقطُّع في عملية التمرير
من المهم أيضًا حصر معالجات اللمس بالعناصر التي تحتاج إليها فقط، لأنّ عناصر اللمس يمكن أن تستهلك قدرًا كبيرًا من النطاق الترددي، لذا من المهم تجنُّب استخدام معالجات اللمس في عناصر التمرير (لأنّ معالجة البيانات قد تتداخل مع تحسينات المتصفّح لتمكين التمرير السريع والسلِس باستخدام اللمس - تحاول المتصفّحات الحديثة التمرير في سلسلة مهام وحدة معالجة الرسومات، ولكن هذا مستحيل إذا كان عليها التحقّق من JavaScript أولاً لمعرفة ما إذا كان التطبيق سيعالج كل حدث لمس). يمكنك الاطّلاع على مثال على هذا السلوك.
لتجنُّب هذه المشكلة، عليك التأكّد من تضمين معالِجات اللمس هناك فقط في جزء صغير من واجهة المستخدم (وليس على <body>
مثلاً من الصفحة مثلاً). باختصار، يمكنك حصر نطاق معالِجات اللمس بقدر الإمكان.
#7: تقنية اللمس المتعدّد
التحدي الأخير المثير للاهتمام هو أنّه على الرغم من أنّنا نشير إلى هذه الواجهة على أنّها واجهة مستخدم "اللمس"، تتوفَّر ميزة "اللمس المتعدد" في جميع أنحاء العالم بشكل عام، أي أنّ واجهات برمجة التطبيقات توفّر أكثر من إدخال لمس واحد في الوقت نفسه. عند بدء إتاحة ميزة اللمس في تطبيقاتك، عليك مراعاة كيفية تأثير اللمسات المتعدّدة في تطبيقك.
إذا كنت تنشئ تطبيقات تعمل بالماوس في الأساس، فأنت معتاد على إنشاء تطبيقات باستخدام نقطة مؤشر واحدة على الأكثر، حيث لا تتوافق الأنظمة عادةً مع مؤشرات ماوس متعددة. بالنسبة إلى العديد من التطبيقات، سيكون عليك ربط أحداث اللمس بواجهة مؤشر واحدة فقط، إلا أنّ معظم أجهزة الإدخال باللمس على سطح المكتب يمكنها التعامل مع إدخالَين متزامنَين على الأقل، ويبدو أنّ معظم الأجهزة الجديدة تتيح 5 إدخالات متزامنة على الأقل. لتطوير لوحة مفاتيح بيانو على الشاشة، قد تحتاج بالطبع إلى إمكانية إدخال عدة إدخالات باللمس متزامنة.
لا تتضمّن واجهات برمجة تطبيقات W3C Touch APIs التي تم تنفيذها حاليًا واجهة برمجة تطبيقات لتحديد عدد نقاط الاتصال التي تتيحها الأجهزة، لذا عليك استخدام أفضل تقدير لعدد نقاط الاتصال التي سيحتاجها المستخدمون، أو بالطبع الانتباه إلى عدد نقاط الاتصال التي تظهر لك في الممارسة والتكيّف معها. على سبيل المثال، في تطبيق البيانو، إذا لم تظهر لك أبدًا أكثر من نقطتَي لمس، قد تحتاج إلى إضافة بعض عناصر واجهة المستخدم "للألحان". تحتوي PointerEvents API على واجهة برمجة تطبيقات لتحديد إمكانات الجهاز.
اللمسات الأخيرة
نأمل أن تكون هذه المقالة قد قدّمت لك بعض الإرشادات حول التحديات الشائعة في تنفيذ تفاعلات اللمس إلى جانب تفاعلات الماوس. من المهم أكثر من أي نصيحة أخرى أن تختبر تطبيقك على الأجهزة الجوّالة والأجهزة اللوحية وأجهزة الكمبيوتر المكتبي المزوّدة بأجهزة تحكّم باللمس وأجهزة تحكّم بالماوس. إذا لم يكن لديك جهاز لمس وماوس، استخدِم ميزة محاكاة أحداث اللمس في Chrome لمساعدتك في اختبار السيناريوهات المختلفة.
من الممكن بل من السهل نسبيًا اتّباع هذه الإرشادات لإنشاء تجارب تفاعلية جذابة تعمل بشكل جيد مع الإدخال باللمس والإدخال باستخدام الماوس، وحتى مع كلا أسلوبَي التفاعل في الوقت نفسه.