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

ديف تابوسكا
"ديف تابوسكا"

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

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

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

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

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

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

التدخل

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

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

وقد دفعنا ذلك إلى تعريف طريقة تفاعلنا على النحو التالي: إذا كان هدف أداة معالجة اللمس أو الاستجابة باللمس هو 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% تقريبًا. نأمل أن نجعل الإعداد التلقائي "صحيح" في المستقبل لجميع مستمعي 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 عليها كي يبقى بإمكان المستخدم الانتقال بشكل عمودي والتكبير أو التصغير كالمعتاد. من الضروري تطبيق إجراء اللمس بشكل صحيح على المتصفحات مثل سطح المكتب Edge الذي يتوافق مع أحداث المؤشر وليس أحداث اللمس. بالنسبة إلى متصفّح Safari على الأجهزة الجوّالة ومتصفّحات الأجهزة الجوّالة القديمة التي لا تتيح استخدام الإجراءات التي تعمل باللمس، يجب أن تستمر أدوات معالجة اللمس التي تعمل باللمس في استدعاء preventDefault حتى عندما يتجاهلها Chrome.

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

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

الخلاصة

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

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