ResizeMonitorer: إنها مثل document.onresize للعناصر

تتيح لك ميزة "ResizeObserver" معرفة ما إذا تغيّر حجم العنصر.

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

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

هذا هو السبب في أنّ ResizeObserver هي إحدى المبادئ الأساسية المفيدة. وهو يتفاعل مع التغييرات في حجم أي من العناصر المرصودة، بغض النظر عن سبب التغيير. يوفر الوصول إلى الحجم الجديد للعناصر المرصودة أيضًا.

التوافق مع المتصفح

  • 64
  • 79
  • 69
  • 13.1

المصدر

API

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

var ro = new ResizeObserver(entries => {
  for (let entry of entries) {
    const cr = entry.contentRect;

    console.log('Element:', entry.target);
    console.log(`Element size: ${cr.width}px x ${cr.height}px`);
    console.log(`Element padding: ${cr.top}px ; ${cr.left}px`);
  }
});

// Observe one or multiple elements
ro.observe(someElement);

بعض التفاصيل

ما الذي يتم الإبلاغ عنه؟

بشكل عام، يُبلغ ResizeObserverEntry عن مربّع المحتوى في عنصر من خلال سمة تُسمىcontentRect، والتي تعرض كائن DOMRectReadOnly. مربع المحتوى هو المربع الذي يمكن وضع المحتوى فيه. إنه مربع الحدود ناقص المساحة المتروكة.

رسم تخطيطي لنموذج مربّع CSS.

من المهم ملاحظة أنّه على الرغم من أنّ ResizeObserver يبلغ عن سمتَي contentRect والمساحة المتروكة، فإنّه يراقب contentRect فقط. لا تخلط بين contentRect ومربّع حدود العنصر. مربّع الإحاطة، كما هو موضّح في getBoundingClientRect()، هو المربّع الذي يحتوي على العنصر بأكمله وعناصره التابعة. وتشكّل ملفات SVG استثناءً للقاعدة، حيث ستُبلِّغ العلامة ResizeObserver عن أبعاد مربّع الإحاطة.

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

  • borderBoxSize
  • contentBoxSize
  • devicePixelContentBoxSize

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

ويقتصر دعم النظام الأساسي لهذه الخصائص على محدودة، ولكن Firefox يتوافق بالفعل مع أول اثنين.

متى يتم الإبلاغ عنه؟

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

لقد فهمت

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

طلب الانضمام

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

const ro = new ResizeObserver(entries => {
  for (let entry of entries) {
    entry.target.style.borderRadius =
        Math.max(0, 250 - entry.contentRect.width) + 'px';
  }
});
// Only observe the second box
ro.observe(document.querySelector('.box:nth-child(2)'));

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

تتيح لك السمة ResizeObserver كتابة رمز واحد يراعي كلا السيناريوهَين. إنّ تغيير حجم النافذة هو حدث يمكن لـ ResizeObserver التقاطه حسب التعريف، ولكن استدعاء appendChild() يؤدي أيضًا إلى تغيير حجم هذا العنصر (ما لم يتم ضبط overflow: hidden)، لأنّه يجب توفير مساحة للعناصر الجديدة. مع وضع ذلك في الاعتبار، يستغرق الأمر بضعة أسطر لتحقيق التأثير المرجو:

const ro = new ResizeObserver(entries => {
  document.scrollingElement.scrollTop =
    document.scrollingElement.scrollHeight;
});

// Observe the scrollingElement for when the window gets resized
ro.observe(document.scrollingElement);

// Observe the timeline to process new messages
ro.observe(timeline);

أنيق جدًا، أليس كذلك؟

من هنا، يمكنني إضافة المزيد من التعليمات البرمجية للتعامل مع الحالة التي يقوم فيها المستخدم بالتمرير لأعلى يدويًا ويرغب في التمرير للالتزام بتلك الرسالة عند وصول رسالة جديدة.

هناك حالة استخدام أخرى تتعلق بأي نوع من العناصر المخصصة التي تقوم بتنسيق خاص بها. حتى ResizeObserver، لم تتوفّر طريقة يمكن الاعتماد عليها لتلقّي إشعارات عندما تتغيّر الأبعاد، وبالتالي يمكن تغيير مظهرها من جديد.

التأثيرات على مدى استجابة الصفحة لتفاعلات المستخدم (INP)

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

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

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

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

  • احرص على أن تكون أدوات اختيار لغة CSS بسيطة قدر الإمكان من أجل تجنُّب الاجتهاد في إعادة احتساب الأنماط. تحدث عمليات إعادة احتساب الأنماط قبل التنسيق مباشرةً، ويمكن أن تؤدي أدوات اختيار لغة CSS المعقدة إلى تأخير عمليات التنسيق.
  • تجنَّب تنفيذ أي إجراء في معاودة الاتصال بـ ResizeObserver قد يؤدي إلى تشغيل عمليات إعادة التدفق الإلزامية.
  • يزيد الوقت اللازم لتحديث تنسيق الصفحة بشكل عام مع زيادة عدد عناصر DOM على الصفحة. وصحيح ما إذا كانت الصفحات تستخدم ResizeObserver أم لا، لكن يمكن أن يصبح العمل المنجز في معاودة الاتصال ResizeObserver مهمًا مع زيادة التعقيد الهيكلي للصفحة.

الخلاصة

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