ماذا لو قلت لك أنّ هناك أكثر من مساحة عرض واحدة؟
BRRRRAAAAAAAMMMMMMMMMM
وإطار العرض الذي تستخدمه الآن هو في الواقع إطار عرض ضمن إطار عرض.
BRRRRAAAAAAAMMMMMMMMMM
وفي بعض الأحيان، تشير البيانات التي يوفّرها لك نموذج DOM إلى أحد مساحات العرض هذه وليس إلى الأخرى.
BRRRRAAAAM… لحظة، ماذا؟
هذا صحيح، إليك نظرة:
إطار عرض التنسيق مقابل إطار العرض المرئي
يعرض الفيديو أعلاه صفحة ويب يتم التمرير فيها وتكبيرها/تصغيرها باستخدام إصبعَين، بالإضافة إلى خريطة مصغّرة على يسار الصفحة تعرض موضع مساحات العرض ضمن الصفحة.
تكون الأمور بسيطة جدًا أثناء التمرير العادي. تمثل المنطقة الخضراء
إطار عرض التنسيق الذي تلتصق به position: fixed
عنصرًا.
تصبح الأمور غريبة عند استخدام ميزة التصغير/التكبير بإصبعَين. يمثّل المربّع الأحمر
إطار العرض المرئي، وهو الجزء من الصفحة الذي يمكننا رؤيته فعليًا. يمكن أن يتحرك إطار العرض هذا بينما تبقى عناصر position: fixed
في مكانها، متّصلة بإطار عرض التصميم. إذا تم التمرير في حدود إطار عرض
التنسيق، يتم سحب إطار عرض التنسيق معه.
تحسين التوافق
للأسف، لا تتّبع واجهات برمجة تطبيقات الويب أسلوبًا متّسقًا في ما يتعلّق بمجال العرض الذي تشير إليه، كما أنّها غير متّسقة على مستوى المتصفّحات.
على سبيل المثال، تعرض element.getBoundingClientRect().y
الإزاحة ضمن
إطار عرض التنسيق. هذا رائع، ولكننا نريد غالبًا معرفة الموضع داخل الصفحة،
لذلك نكتب:
element.getBoundingClientRect().y + window.scrollY
ومع ذلك، تستخدم العديد من المتصفّحات إطار العرض المرئي لنظام التشغيل window.scrollY
، ما يعني أنّه
يتعطّل الرمز البرمجي أعلاه عندما يكبّر المستخدم المحتوى باستخدام إصبعَين.
يغيّر الإصدار 61 من Chrome العنصر window.scrollY
للإشارة إلى مساحة عرض التنسيق بدلاً من ذلك،
ما يعني أنّ الرمز أعلاه يعمل حتى عند التكبير/التصغير باستخدام إصبعَين. في الواقع، تغيّر المتصفّحات ببطء جميع السمات الموضعية للإشارة إلى إطار عرض التصميم.
باستثناء موقع جديد واحد…
إتاحة إطار العرض المرئي للنص البرمجي
تعرض واجهة برمجة تطبيقات جديدة إطار العرض المرئي على النحو التالي: window.visualViewport
. هذه مسودة مواصفات، وقد حصلت على موافقة على مستوى جميع المتصفّحات، وسيتم طرحها في الإصدار 61 من Chrome.
console.log(window.visualViewport.width);
في ما يلي المعلومات التي يوفّرها window.visualViewport
:
visualViewport مكانًا للإقامة |
|
---|---|
offsetLeft
|
المسافة بين الحافة اليسرى لمساحة العرض المرئية ومساحة عرض التنسيق، بالبكسل في CSS |
offsetTop
|
المسافة بين الحافة العلوية لإطار العرض المرئي وإطار عرض التنسيق، بالبكسل في CSS |
pageLeft
|
المسافة بين الحافة اليسرى لإطار العرض المرئي والحافة اليسرى للمستند، بالبكسل في CSS |
pageTop
|
المسافة بين الحافة العلوية لمساحة العرض المرئية والحافة العلوية للمستند، بالبكسل في CSS |
width
|
عرض إطار العرض المرئي بالبكسل في CSS |
height
|
ارتفاع إطار العرض المرئي بالبكسل في CSS |
scale
|
النطاق الذي يتم تطبيقه من خلال التصغير أو التكبير بإصبعَين إذا كان المحتوى ضعف حجمه بسبب
التكبير، سيتم عرض 2 . ولا يتأثر ذلك
devicePixelRatio .
|
هناك أيضًا حدثان:
window.visualViewport.addEventListener('resize', listener);
فعاليات visualViewport |
|
---|---|
resize
|
يتم تشغيله عند تغيير width أو height أو
scale .
|
scroll
|
يتم تشغيله عند تغيير offsetLeft أو offsetTop .
|
عرض توضيحي
تم إنشاء الفيديو في بداية هذه المقالة باستخدام visualViewport
،
يمكنك مشاهدته في الإصدار 61 من Chrome والإصدارات الأحدث. ويستخدم
visualViewport
لتثبيت الخريطة المصغّرة في أعلى يسار مساحة العرض المرئية، ويطبّق مقياسًا عكسيًا لكي تظهر دائمًا بالحجم نفسه،
على الرغم من التصغير/التكبير بإصبعَين.
الأخطاء
لا يتم تشغيل الأحداث إلا عند تغيير إطار العرض المرئي.
قد يبدو هذا الأمر واضحًا، ولكنني لم أدرك ذلك عندما بدأت في
اللعب مع visualViewport
.
إذا تم تغيير حجم إطار عرض التنسيق بدون تغيير حجم إطار العرض المرئي، لن تتلقّى حدث
resize
. ومع ذلك، من غير المعتاد أن يتم تغيير حجم إطار عرض التنسيق بدون
تغيير العرض/الارتفاع في إطار العرض البصري أيضًا.
المشكلة الحقيقية هي الانتقال للأعلى أو للأسفل. في حال حدوث الانتقال للأعلى أو للأسفل، ولكن ظلّ إطار العرض المرئي
ثابتًا بالنسبة إلى إطار عرض التنسيق، لن تتلقّى حدث scroll
في visualViewport
، وهذا أمر شائع جدًا. أثناء التنقّل العادي في المستند، يبقى إطار العرض المرئي مُقفَلاً في أعلى يمين إطار عرض visualViewport
، لذا لا يتم تنشيط scroll
عند visualViewport
.
إذا كنت تريد معرفة كل التغييرات التي تطرأ على مساحة العرض المرئية، بما في ذلك
pageTop
وpageLeft
، عليك الاستماع إلى حدث الانتقال في النافذة
أيضًا:
visualViewport.addEventListener('scroll', update);
visualViewport.addEventListener('resize', update);
window.addEventListener('scroll', update);
تجنُّب تكرار العمل مع مستمعين متعدّدين
على غرار الاستماع إلى scroll
وresize
في النافذة، من المرجّح أن تُطلِب
نوعًا من دالة "update" نتيجةً لذلك. ومع ذلك، من الشائع أن تحدث العديد من
هذه الأحداث في الوقت نفسه. إذا عدّل المستخدم حجم النافذة، سيتم
تشغيل resize
، ولكن في كثير من الأحيان سيتم تشغيل scroll
أيضًا. لتحسين الأداء، تجنَّب
معالجة التغيير عدّة مرات:
// Add listeners
visualViewport.addEventListener('scroll', update);
visualViewport.addEventListener('resize', update);
addEventListener('scroll', update);
let pendingUpdate = false;
function update() {
// If we're already going to handle an update, return
if (pendingUpdate) return;
pendingUpdate = true;
// Use requestAnimationFrame so the update happens before next render
requestAnimationFrame(() => {
pendingUpdate = false;
// Handle update here
});
}
لقد أرسلتُ طلبًا بشأن المواصفات، لأنّني أعتقد أنّه قد تكون هناك
طريقة أفضل، مثل حدث update
واحد.
عدم عمل معالِجات الأحداث
لا يعمل ما يلي بسبب خطأ في Chrome:
يتضمّن أخطاء: يستخدم معالج حدث
visualViewport.onscroll = () => console.log('scroll!');
بدلاً من ذلك:
يعمل - يستخدم أداة معالجة حدث
visualViewport.addEventListener('scroll', () => console.log('scroll'));
يتم تقريب قيم الإزاحة
أعتقد (وأتمنى) أنّ هذا خطأ آخر في Chrome.
يتم تقريب offsetLeft
وoffsetTop
، ما يؤدي إلى عدم الدقة بعد أن
يكبّر المستخدِم الصورة. يمكنك الاطّلاع على المشاكل المتعلّقة بهذا أثناء العرض التجريبي. إذا كبّر المستخدم الصورة وحرّكها
ببطء، تنتقل الخريطة المصغّرة بين وحدات البكسل التي لم يتم تكبيرها.
معدّل الأحداث بطيء
مثل أحداث resize
وscroll
الأخرى، لا يتم تشغيل هذه الأحداث في كل لقطة،
خاصةً على الأجهزة الجوّالة. يمكنك ملاحظة ذلك أثناء العرض التجريبي. بعد تكبير/تصغير الشاشة باستخدام إصبعَين، تواجه الخريطة المصغّرة صعوبة في البقاء مقفلة على مساحة العرض.
تسهيل الاستخدام
في العرض التجريبي، استخدمت visualViewport
للتغلب على ميزة التصغير/التكبير باستخدام إصبعَين. هذا منطقي في هذا العرض الترويجي تحديدًا، ولكن
عليك التفكير جيدًا قبل تنفيذ أي إجراء يتجاوز الرغبة
التي يشعر بها المستخدم في التكبير.
يمكن استخدام visualViewport
لتحسين سهولة الاستخدام. على سبيل المثال، إذا كان المستخدم
يكبِّر الصورة، يمكنك اختيار إخفاء عناصر position: fixed
الزخرفية، لتجنُّب
عرقلة المستخدم. ومع ذلك، يجب الحرص على عدم إخفاء محتوى
يحاول المستخدم الاطّلاع عليه عن كثب.
يمكنك نشر البيانات في خدمة إحصاءات عندما يكبّر المستخدم الصورة. يمكن أن يساعدك ذلك في تحديد الصفحات التي يواجه المستخدمون صعوبة في استخدامها عند استخدام مستوى التكبير/التصغير التلقائي.
visualViewport.addEventListener('resize', () => {
if (visualViewport.scale > 1) {
// Post data to analytics service
}
});
هذا كل ما في الأمر! visualViewport
هي واجهة برمجة تطبيقات رائعة تحلّ مشكلات التوافق
أثناء التنفيذ.