جعل التمرير باللمس سريعًا بشكل تلقائي

Dave Tapuska
Dave Tapuska

ندرك أنّ سرعة الاستجابة لتحريك الصفحة للأعلى أو للأسفل أمر بالغ الأهمية لتفاعل المستخدم مع الموقع الإلكتروني على الأجهزة الجوّالة، إلا أنّ أدوات الاستماع إلى أحداث اللمس غالبًا ما تتسبّب في حدوث مشاكل خطيرة في سرعة الأداء. يعالج Chrome هذه المشكلة من خلال السماح لمعالجي أحداث اللمس بأن يكونوا سلبيين (تمرير الخيار {passive: true} إلى addEventListener()) وطرح واجهة برمجة التطبيقات Pointer events. هذه الميزات رائعة لعرض محتوى جديد في النماذج التي لا تحظر التمرير، ولكن يجد المطوّرون أحيانًا صعوبة في فهمها واستخدامها.

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

في حالات نادرة، يمكن أن يؤدي هذا التغيير إلى الانتقال إلى أسفل الصفحة أو أعلاها بدون قصد. يمكن عادةً معالجة هذه المشكلة بسهولة من خلال تطبيق أسلوب touch-action: none على العنصر الذي لا يجب أن يتم التمرير فيه. يمكنك مواصلة القراءة للاطّلاع على التفاصيل ومعرفة ما إذا كنت متأثرًا بالتغييرات وكيفية التعامل معها.

الخلفية: تؤدي الأحداث القابلة للإلغاء إلى إبطاء سرعة صفحتك

إذا استدعيت preventDefault() في حدث touchstart أو الحدث touchmove الأول، ستمنع الانتقال للأعلى أو للأسفل. تكمن المشكلة في أنّ المستمعين لن يتصلوا غالبًا بـ preventDefault()، ولكن على المتصفّح الانتظار حتى ينتهي الحدث للتأكّد من ذلك. وتعمل "أدوات معالجة الأحداث السلبية" التي يحدّدها المطوّر على حلّ هذه المشكلة. عند إضافة حدث لمس باستخدام عنصر {passive: true} كمَعلمة ثالثة في معالج الحدث، يعني ذلك أنّك تُعلم المتصفّح بأنّ مستمع touchstart لن يُطلِب preventDefault() ويمكن للمتصفّح تنفيذ الانتقال للأعلى أو للأسفل بأمان بدون حظر المستمع. على سبيل المثال:

window.addEventListener("touchstart", func, {passive: true} );

التدخل

هدفنا الرئيسي هو تقليل الوقت الذي يستغرقه تعديل الشاشة بعد لمس المستخدم للشاشة. لفهم استخدام touchstart وtouchmove، أضافنا مقاييس لتحديد عدد المرات التي حدث فيها سلوك حظر التمرير.

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

دفعنا ذلك إلى تحديد تدخلنا على النحو التالي: إذا كان الهدف من مستمع touchstart أو touchmove هو window أو document أو body، سنضبط passive تلقائيًا على true. وهذا يعني أنّ الرموز البرمجية مثل:

window.addEventListener("touchstart", func);

تصبح مساوية لما يلي:

window.addEventListener("touchstart", func, {passive: true} );

سيتم الآن تجاهل المكالمات إلى preventDefault() داخل المشغّل.

يعرض الرسم البياني أدناه الوقت المستغرَق في أعلى% 1 من عمليات التمرير من وقت ملامسة المستخدِم للشاشة للتمرير إلى وقت تعديل الشاشة. تنطبق هذه البيانات على جميع المواقع الإلكترونية في Chrome لأجهزة Android. قبل تفعيل التدخل، كانت نسبة% 1 من عمليات التمرير تستغرق أكثر من 400 ملي ثانية بقليل. تم خفض هذا الوقت الآن إلى أكثر من 250 ملي ثانية في الإصدار التجريبي من Chrome 56، أي بنسبة انخفاض تبلغ ‎38% تقريبًا. نأمل في المستقبل أن نجعل قيمةparam.passive.true هي الإعداد التلقائي لجميع مستمعي touchstart وtouchmove، وخفض هذه القيمة إلى أقل من 50 ملي ثانية.

الرسم البياني لأوقات الانتقال إلى أعلى الصفحة في% 1 من التطبيقات

الكسر والإرشادات

في الغالبية العظمى من الحالات، لن يتم ملاحظة أيّ انقطاع. ولكن عندما يحدث تعطُّل، يكون العرض الأكثر شيوعًا هو الانتقال للأعلى أو للأسفل عندما لا تريد ذلك. في حالات نادرة، قد يلاحظ المطوّرون أيضًا أحداث نقرة غير متوقّعة (عندما لا يكون preventDefault() متوفّرًا في مستمع touchend).

في الإصدار 56 من Chrome والإصدارات الأحدث، ستسجِّل أدوات المطوّرين تحذيرًا عند استدعاء preventDefault() في حدث يكون فيه التدخل نشطًا.

touch-passive.html:19 Unable to preventDefault inside passive event listener due to target being treated as passive. See https://www.chromestatus.com/features/5093566007214080

يمكن لتطبيقك تحديد ما إذا كان قد واجه هذه المشكلة في الواقع من خلال التحقّق مما إذا كان استدعاء preventDefault قد كان له أي تأثير من خلال السمة defaultPrevented.

تبيّن لنا أنّه يمكن إصلاح الغالبية العظمى من الصفحات المتأثّرة بسهولة نسبية من خلال تطبيق الخاصية touch-action CSS كلما أمكن ذلك. إذا أردت منع جميع عمليات التمرير في المتصفّح و التكبير/التصغير داخل عنصر، طبِّق touch-action: none عليه. إذا كان لديك عرض دوار أفقي، ننصحك بتطبيق touch-action: pan-y pinch-zoom عليه كي يظل بإمكان المستخدم الانتقال عموديًا وتكبير/تصغير المحتوى كالمعتاد. من الضروري تطبيق ‎touch-action بشكل صحيح على المتصفّحات، مثل Edge المتوافق مع أحداث المؤشر وليس أحداث اللمس، على أجهزة الكمبيوتر المكتبي. بالنسبة إلى متصفّح Safari للأجهزة الجوّالة والمتصفّحات المتوافقة الأقدم للأجهزة الجوّالة التي لا تتيح استخدام الإجراءات المستندة إلى اللمس، يجب أن يواصل مستمعو اللمس استدعاء preventDefault حتى إذا تجاهله Chrome.

في الحالات الأكثر تعقيدًا، قد يكون من الضروري أيضًا الاعتماد على أحد الإجراءات التالية:

  • إذا كانت أداة معالجة touchstart تستدعي preventDefault()، تأكَّد من أنّه يتم أيضًا استدعاء ‎(preventdefault())‎ من أدوات معالجة touchend المرتبطة لمواصلة منع إنشاء أحداث النقرات وسلوك النقر التلقائي الآخر.
  • الخطوة الأخيرة (والتي لا يُنصح بها) هي تمرير {passive: false} إلى addEventListener() لتجاوز السلوك التلقائي. يُرجى العِلم أنّه عليك رصد الميزة لمعرفة ما إذا كان وكيل المستخدم يتوافق معEventListenerOptions.

الخاتمة

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

على الرغم من أنّه لا يزال من الضروري إجراء ذلك في Safari على الأجهزة الجوّالة، يجب ألا تعتمد المواقع الإلكترونية على استدعاء preventDefault() داخل touchstart ومُشغّلات touchmove لأنّه لم يعُد من المؤكد أن يتم تنفيذ ذلك في Chrome. على المطوّرين تطبيق خاصية touch-action CSS على العناصر التي يجب إيقاف الانتقال فيها باللوحة الماوس والتكبير/التصغير لإشعار المتصفّح قبل حدوث أي أحداث لمس. لإيقاف السلوك التلقائي للنقر (مثل إنشاء حدث النقر)، يمكنك استدعاء preventDefault() داخل مستمع touchend.