الثقة جيدة، والملاحظة أفضل: الإصدار 2 من أداة مراقبة تقاطع

يضيف الإصدار 2 من أداة مراقبة التقاطع إمكانية مراقبة التقاطعات في حد ذاتها، بالإضافة إلى إمكانية اكتشاف ما إذا كان العنصر المتقاطع مرئيًا وقت التقاطع.

الإصدار الأول من أداة Intersection Observer هي إحدى واجهات برمجة التطبيقات التي ربما تكون المفضّلة على مستوى العالم، والآن بعد أن أصبح متصفّح Safari يدعمها أيضًا، أصبح قابلاً للاستخدام في النهاية عالميًا في جميع المتصفحات الرئيسية. لمراجعة سريعة لواجهة برمجة التطبيقات، ننصح بمشاهدة نصيحة مميّزة من Surma بشأن الإصدار 1 من Intersection Observer والمضمّن أدناه. يمكنك أيضًا قراءة المقالة المفصّلة التي كتبتها "سورما". استخدَم المستخدمون الإصدار 1 من Intersection Observer لمجموعة كبيرة من حالات الاستخدام، مثل التحميل البطيء للصور والفيديوهات، تلقّي إشعارات عند وصول العناصر إلى position: sticky، تفعيل أحداث الإحصاءات، وغير ذلك الكثير.

للاطّلاع على التفاصيل الكاملة، يمكنك الاطّلاع على مستندات Intersection Observer على MDN، ولكن في ما يلي تذكير موجز بكيفية ظهور واجهة برمجة التطبيقات Intersection Observer v1 في أبسط الحالات:

const onIntersection = (entries) => {
  for (const entry of entries) {
    if (entry.isIntersecting) {
      console.log(entry);
    }
  }
};

const observer = new IntersectionObserver(onIntersection);
observer.observe(document.querySelector('#some-target'));

ما هي المشاكل المتعلّقة بالإصدار 1 من Intersection Observer؟

للتوضيح، إنّ الإصدار 1 من Intersection Observer رائع، ولكنه ليس مثاليًا. هناك بعض الحالات الخاصة التي لا تتوافق فيها واجهة برمجة التطبيقات مع المتطلبات. لنلقِ نظرة عن كثب. يمكن أن تُعلمك واجهة برمجة التطبيقات Intersection Observer v1 عندما يتم الانتقال إلى عنصر في مجال عرض النافذة، ولكنّها لا تُعلمك ما إذا كان العنصر مغطّى بأي محتوى آخر للصفحة (أي عندما يكون العنصر محجوبًا) أو ما إذا كان قد تم تعديل العرض المرئي للعنصر باستخدام تأثيرات مرئية مثل transform وopacity filter وما إلى ذلك، ما يمكن أن يجعله غير مرئي بشكل فعّال.

بالنسبة إلى أحد العناصر في مستند المستوى الأعلى، يمكن تحديد هذه المعلومات من خلال تحليل نموذج كائن المستند (DOM) عبر JavaScript، على سبيل المثال من خلال DocumentOrShadowRoot.elementFromPoint() ثم التعمّق أكثر. في المقابل، لا يمكن الحصول على المعلومات نفسها إذا كان العنصر المعني موجودًا في إطار iframe تابع لجهة خارجية.

ما أهمية مستوى الظهور الفعلي؟

يجذب الإنترنت، للأسف، جهات سيئة بنوايا أسوأ. على سبيل المثال، قد يتم تحفيز ناشر مشبوه يعرض إعلانات "الدفع بالنقرة" على موقع إلكتروني يتضمّن محتوى بهدف خداع المستخدمين لكي ينقروا على إعلاناته لزيادة عائد الإعلانات الذي يحصل عليه الناشر (على الأقل لمدة قصيرة إلى أن ترصده شبكة الإعلانات). وعادةً ما يتم عرض هذه الإعلانات في إطارات iframe. وإذا أراد الناشر حثّ المستخدمين على النقر على هذه الإعلانات، يمكنهم جعل إطارات iframe للإعلان شفافة تمامًا من خلال تطبيق قاعدة CSS iframe { opacity: 0; } وتركيب إطارات iframe فوق عنصر جذاب، مثل فيديو عن قطة لطيفة قد يرغب المستخدمون في النقر عليها. ويُعرف هذا الإجراء باسم التصيُّد بالنقر. يمكنك مشاهدة هجوم خداع بالنقر في الجزء العلوي من هذا العرض التجريبي (جرِّب "مشاهدة" فيديو القطة وتفعيل "وضع الخداع"). ستلاحظ أنّ الإعلان في إطار iframe "يظن" أنّه تلقّى نقرات مشروعة، حتى لو كان شفّافًا تمامًا عند النقر عليه (بطريقة مصطنعة).

خداع المستخدِم لكي ينقر على إعلان من خلال تصميمه بشكل شفاف وتضمينه فوق عنصر جذاب

كيف يحلّ الإصدار 2 من Intersection Observer هذه المشكلة؟

يقدّم الإصدار 2 من Intersection Observer مفهوم تتبُّع "مستوى الرؤية" الفعلي لعنصر مستهدف، كما يحدّده الشخص. من خلال ضبط خيار في مُنشئIntersectionObserver، ستحتوي المثيلات المتعلّقة بالحدود المتلاقية IntersectionObserverEntry على حقل منطقي جديد باسم isVisible. إنّ قيمة true لـ isVisible هي ضمانة قوية من التنفيذ الأساسي بأنّ العنصر المستهدَف غير محجوب تمامًا عن الرؤية بواسطة محتوى آخر وأنّه لم يتم تطبيق أيّ تأثيرات مرئية من شأنها تغيير طريقة عرضه على الشاشة أو تشويهها. في المقابل، تعني قيمة false أنّ التنفيذ لا يمكنه تقديم هذا الضمان.

من التفاصيل المهمة في المواصفات أنّه يُسمح بتسجيل نتائج سلبية خاطئة (أي ضبط isVisible على false حتى عندما يكون العنصر المستهدَف مرئيًا بالكامل وغير معدَّل). لأسباب تتعلّق بالأداء أو لأسباب أخرى، تقتصر المتصفّحات على استخدام المربّعات الحدودية والأشكال الهندسية المستقيمة، ولا تحاول تحقيق نتائج دقيقة على مستوى البكسل للتعديلات مثل border-radius.

مع ذلك، لا يُسمح بـ النتائج الموجبة الخاطئة تحت أي ظرف من الظروف (أي ضبط isVisible على true عندما لا يكون العنصر المستهدف مرئيًا بالكامل وغير معدّل).

كيف يبدو الرمز الجديد عمليًا؟

تستخدم الدالة الإنشائية IntersectionObserver الآن خاصيتَي ضبط إضافيتين: delay وtrackVisibility. ‫delay هو رقم يشير إلى الحد الأدنى من التأخير بالمللي ثانية بين الإشعارات الواردة من المراقِب لهدف معيّن. ‫trackVisibility هو قيمة منطقية تشير إلى ما إذا كان المُراقب سيتتبّع التغييرات في مستوى رؤية الهدف.

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

وفقًا لحال المواصفات الحالية، يتم احتساب مستوى الرؤية على النحو التالي:

  • إذا كانت سمة trackVisibility للمراقب هي false، سيُعتبَر الهدف مرئيًا. يتوافق ذلك مع السلوك الحالي v1.

  • إذا كان الهدف يتضمّن مصفوفة تحويل فعّالة غير الترجمة ثنائية الأبعاد أو التكبير التناسبي ثنائي الأبعاد، يُعدّ الهدف غير مرئي.

  • إذا كان الهدف أو أي عنصر في سلسلة الكتل التي تحتوي عليه يتضمن معدل تعتيم فعال بخلاف 1.0، يُعتبر الهدف غير مرئي.

  • إذا تم تطبيق أي فلاتر على الهدف أو أي عنصر في سلسلة الكتل التي يحتوي عليها، يُعتبر الهدف غير مرئي.

  • إذا لم يتمكّن التنفيذ من ضمان أنّ الهدف غير محجوب تمامًا من خلال محتوى الصفحة الآخر، يُعتبر الهدف غير مرئي.

ويعني هذا أن عمليات التنفيذ الحالية اعتيادية مع ضمان وضوح الرؤية. على سبيل المثال، سيؤدي تطبيق فلتر ألوان رمادية غير محسوس تقريبًا مثل filter: grayscale(0.01%) أو ضبط شفافية غير مرئية تقريبًا باستخدام opacity: 0.99 إلى جعل العنصر غير مرئي.

في ما يلي نموذج رمز برمجي قصير يوضّح ميزات واجهة برمجة التطبيقات الجديدة. يمكنك الاطّلاع على منطق تتبُّع النقرات بشكل عملي في القسم الثاني من العرض التوضيحي (ولكن يمكنك تجربة "مشاهدة" الفيديو الذي يتناول الجراء). احرص على تفعيل "وضع الخداع" مرة أخرى لتحويل نفسك على الفور إلى ناشر مشبوه ومعرفة كيف يمنع الإصدار 2 من Intersection Observer تتبُّع النقرات على الإعلانات غير المشروعة. هذه المرة، نستخدم الإصدار 2 من Intersection Observer. 🎉

تمنع الإصدار 2 من Intersection Observer النقر غير المقصود على إعلان.

<!DOCTYPE html>
<!-- This is the ad running in the iframe -->
<button id="callToActionButton">Buy now!</button>
// This is code running in the iframe.

// The iframe must be visible for at least 800ms prior to an input event
// for the input event to be considered valid.
const minimumVisibleDuration = 800;

// Keep track of when the button transitioned to a visible state.
let visibleSince = 0;

const button = document.querySelector('#callToActionButton');
button.addEventListener('click', (event) => {
  if ((visibleSince > 0) &&
      (performance.now() - visibleSince >= minimumVisibleDuration)) {
    trackAdClick();
  } else {
    rejectAdClick();
  }
});

const observer = new IntersectionObserver((changes) => {
  for (const change of changes) {
    // ⚠️ Feature detection
    if (typeof change.isVisible === 'undefined') {
      // The browser doesn't support Intersection Observer v2, falling back to v1 behavior.
      change.isVisible = true;
    }
    if (change.isIntersecting && change.isVisible) {
      visibleSince = change.time;
    } else {
      visibleSince = 0;
    }
  }
}, {
  threshold: [1.0],
  // 🆕 Track the actual visibility of the element
  trackVisibility: true,
  // 🆕 Set a minimum delay between notifications
  delay: 100
}));

// Require that the entire iframe be visible.
observer.observe(document.querySelector('#ad'));

شكر وتقدير

نشكر سيمون فنسنت، يوآف ويس، وماتياس بينينز على مراجعة هذه المقالة، وكذلك ستيفان زاغر بدوره على مراجعة الميزة وتنفيذها في Chrome. الصورة الرئيسية لسيرجي سيمن على Unsplash