اذهب إلى المحتوى

ضبط مقاسات نافذة صفحة الويب في جافاسكربت وارتباطها بعملية التمرير (scrolling)


عائشة ميرا

هل تتساءل عن كيفية الحصول على طول وعرض نافذة المتصفح؟ وكيف لك أن تعرف الطول والعرض الكلي للصفحة بما فيه الجزء الذي لا يُؤشِر عليه شريط التمرير (الجزء من الصفحة غير الظاهر في النافذة)؟ وكيف يمكن تمرير محتوى الصفحة باستعمال لغة جافاسكربت؟ فيما يلي الأجوبة الشافية لكل هذه التساؤلات.

يمكن، في أغلب هذه الحالات، استعمال العنصر الجذر للصفحة document.documentElement الذي يقابِل الوسم <html>، بالإضافة إلى بعض الدوالّ والخاصيات التي يُستحسن أخذها في الحسبان نظرًا لأهميتها.

طول وعرض النافذة

تُستخدم الخاصيتان clientHeight وclientWidth لمعرفة طول وعرض النافذة.

001documentElementClientHeightWidth.png

حيث تُظهِرالتعليمة، في المثال التالي، طول نافذة المتصفح:

alert( document.documentElement.clientHeight );

ملاحظة: لا تستعمل window.innerWidth وwindow.innerHeight

تدعم المتصفحات الخاصيتين window.innerWidth وwindow.innerHeight، ويبدو أنهما تتوافقان مع ما نريده، فلماذا لا نستخدمهما بدلًا من الخاصيتين اللّتان ذكرناهما سابقا؟

في حالة وجود شريط تمرير في الصفحة، تعطي الخاصيتان clientHeight وclientWidth طول وعرض النافذة بعد طرح عرض شريط التمرير منه. أو بعبارة أخرى، تعطيان طول وعرض الجزء الظاهر من الصفحة والمخصص للمحتوى. وتعطي الخاصيتان window.innerWidth وwindow.innerHeight الطول والعرض الكليين للنافذة بما فيهما عرض شريط التمرير.

في حالة ما إذا كان لدينا شريط تمرير يشغل مساحة ما من النافذة، تعطي التعليمتان التاليتان نتائج مختلفة:

alert( window.innerWidth ); // العرض الكلي للنافذة
alert( document.documentElement.clientWidth ); // عرض النافذة بعد طرح عرض شريط التمرير منه

نحتاج، في أغلب الحالات، معرفة عرض النافذة المتاح (المخصص للمحتوى)، لرسم شيء ما أو وضعه، أي دون احتساب عرض شريط التمرير إن وُجد، لذا علينا استعمال الخاصيتين documentElement.clientHeight وdocumentElement.clientWidth.


ملاحظة: التعليمة DOCTYPE مهمة

لاحظ أن الخاصيات رفيعة المستوى المتعلقة بالهندسة يمكن أن لا تعمل بالشكل المطلوب إذا لم يحوي ملف HTML التعليمة <!DOCTYPE HTML> ، فمن الممكن أن تحدث أشياء غريبة بسبب ذلك. أضف دائمًا إذًا التعليمة DOCTYPE عند كتابة شيفرة HTML على الطريقة العصرية.


طول وعرض الصفحة

نظريا، وبما أن العنصر الجذر للصفحة هو document.documentElement، ويضُم كلّ المحتوى، يمكن قياس العرض والطول الكليين للصفحة باستعمال الخاصيتين document.documentElement.scrollWidth وdocument.documentElement.scrollHeight، ولكن هاتين الخاصيتين، عند استعمالهما على هذا العنصر، لا تعملان بالشكل المطلوب إن لم يكن هناك شريط تمرير في كلّ من المتصفحات Chrome/Safari/Opera، حيث يمكن أن تعطي الخاصية documentElement.scrollHeight قيمةً أصغر من القيمة التي تعطيها الخاصية documentElement.clientHeight. يبدو الأمر غريبا نوعا ما، أليس كذلك؟

للحصول إذًا على القيمة الصحيحة للطول الكلي للصفحة، علينا أخذ أكبر قيمة من بين القيم التالية:

let scrollHeight = Math.max(
  document.body.scrollHeight, document.documentElement.scrollHeight,
  document.body.offsetHeight, document.documentElement.offsetHeight,
  document.body.clientHeight, document.documentElement.clientHeight
);
alert('Full document height, with scrolled out part: ' + scrollHeight);

لماذا يحدث ذلك؟ يُستحسن عدم طرح هذا السؤال لأن هذه التناقضات موجودة منذ زمن ولا تخضع لتفكير منطقي "ذكي".

حساب إحداثيات الموضع الحالي لعنصر ما

تملك عناصر تمثيل الصفحة ككائن DOM خاصيتين تحملان إحداثيات موضعها من الصفحة وهما: elem.scrollLeft وelem.scrollTop. فبالنسبة لموضِع النافذة، تعمل الخاصيتان document.documentElement.scrollLeft وdocument.documentElement.scrollTop في أغلب المتصفحات، عدا تلك التي تعتمد على محرك WebKit مثل المتصفح Safari (يوّلد استعمالها الخطأ البرمجي 5991)، حيث ينبغي في هذه الحالة استعمال document.body بدلا من document.documentElement.

ومن حسن الحظ أنه ليس علينا على الإطلاق تذكُّر كلّ هذه الخاصيات، حيث توجد خاصيتان غيرهما تعطيان الموضع الحالي للنافدة، إنهما الخاصيتان window.pageXOffset وwindow.pageYOffset، وهما خاصيتان قابلتان فقط للقراءة.

alert('Current scroll from the top: ' + window.pageYOffset);
alert('Current scroll from the left: ' + window.pageXOffset);

التمرير باستعمال الدوال scrollTo وscrollBy وscrollIntoView


ملاحظة هامة

لا يمكن تمرير الصفحة إلّا بعد البناء الكلي لنموذج تمثيل الصفحة ككائن (DOM)، فمن غير الممكن كتابة شيفرة لتمرير الصفحة ووضعها في الجزء <head> أي تنفيذها قبل أن تجهز الصفحة فلن يعمل ذلك حتما.


ويمكن تمرير العناصر العادية بتغيير قيم الخاصيتين scrollTop وscrollLeft، كما يمكن عمل الشيء نفسه للصفحة باستعمال الخاصيتين document.documentElement.scrollLeft وdocument.documentElement.scrollTop، عدا في المتصفح Safari (حيث ينبغي استخدام الخاصيتين document.body.scrollLeft وdocument.body.scrollTop بدلا منها).

وهناك أيضا طريقةٌ بديلةٌ، أبسط من الأولى، تعمل في كافة المتصفحات، وتكون باستعمال الدالّتين window.scrollBy(x,y)‎ وwindow.scrollTo(pageX,pageY)‎.

تحرّك الدالّة scrollBy(x,y)‎ النافذة من مكانها الحالي بمقدار معين. حيث تُحرِك التعليمة window.scrollBy(0,10)‎ مثلا الصفحة إلى الأسفل بمقدار عشرة بكسل.

وتحرِّك الدالّة scrollTo(pageX,pageY)‎ الصفحة إلى موضعٍ ذي إحداثياتٍ مطلقةٍ. بحيث تكون إحداثيات الركن العلوي الأيسر للجزء الظاهر من الصفحة هي (pageX, pageY) إنطلاقا من الركن العلوي الأيسر للصفحة. تعمل هذه الدالّة تماما كما لو أننا نُسنِد قِيَمًا للخاصيتين scrollLeft وscrollTop.

مثلًا لتحريك النافذة إلى نقطة البداية (العودة إلى أعلى الصفحة)، يمكن استعمال التعليمة window.scrollTo(0,0)‎. وتعمل هذه الدوالّ بنفس الطريقة (تعطي النتائج نفسها) على كلّ المتصفحات.

الدالة scrollIntoView

دعنا نكمل ما بدأناه بشرح الدالّة elem.scrollIntoView(top)‎. ينتج عن مناداة هذه الدالّة تمرير الصفحة بحيث تجعل العنصر elem ظاهرًا، ولها وسيط واحد:

  • إذا كانت قيمة الوسيط top تساوي true (وهي القيمة المبدئية -الافتراضية)، تُمرَّر الصفحة بحيث يظهر العنصر elem أعلى النافذة فتتطابق حافته العلوية مع أعلى النافذة.
  • وإذا كانت قيمة الوسيط top تساوي false، تُمرَّر الصفحة بحيث يظهر العنصر elem أسفل النافذة فتتطابق حافته السفلى مع أسفل النافذة.

مثال: إذا كان لدينا زر، فإن هذه التعليمة this.scrollIntoView()‎ تُحرِك الصفحة بحيث يظهر هذا الزر أعلى النافذة. أما هذه التعليمة this.scrollIntoView(false)‎، فتُحرِك الصفحة بحيث يظهر الزر أسفل النافذة.

تثبيط قابلية التمرير

نحتاج أحيانا إلى جعل الصفحة غير قابلة للتمرير، فنرغب مثلًا في إخفائها وراء رسالة طويلة للفت انتباه الزائر وحمله على التفاعل مع الرسالة وليس مع الصفحة. وهنا يكفي إسناد القيمة "hidden" للخاصية document.body.style.overflow حيث تثبِّت (تجمِّد) هذه التعليمة الصفحة في موضعها الحالي.

فلتجرب ذلك باستعمال التعليمتين document.body.style.overflow="hidden" و document.body.style.overflow="".

هنا، تثبِّط التعليمة الأولى قابلية التحريك، أما التعليمة الثانية فتعاود تفعيلها. ويمكننا استعمال هذه الطريقة لتجميد/تثبيت عناصر أخرى أيضا، ليس العنصر document.body فقط.

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

الخلاصة

  • لمعرفة طول/عرض الجزء الظاهر من الصفحة (طول/عرض مساحة المحتوى) نستعمل الخاصيتين document.documentElement.clientWidth/Height. *لمعرفة الطول/العرض الكلي للصفحة بما فيها الجزء غير الظاهر في النافذة نبحث عن أكبر قيمة من بين القيم التالية:
let scrollHeight = Math.max(
  document.body.scrollHeight, document.documentElement.scrollHeight,
  document.body.offsetHeight, document.documentElement.offsetHeight,
  document.body.clientHeight, document.documentElement.clientHeight
);
  • لقراءة إحداثيات موضع الجزء الظاهر من الصفحة إنطلاقا من الركن العلوي الأيسر للصفحة نستعمل الخاصيتين window.pageYOffset/pageXOffset.
  • ولتغيير الموضع الحالي للنافذة نستعمل الدوالّ التالية:
    • window.scrollTo(pageX,pageY): التحريك نحو الموضع ذي الإحداثيات المطلقة (pageX,pageY).
    • window.scrollBy(x,y) : التحريك بمقدار (x,y) انطلاقا من الموضع الحالي.
    • elem.scrollIntoView(top): التحريك لجعل العنصر elem ظاهرًا، أي تحريكه بحيث يتطابق مع أعلى أو أسفل النافذة حسب قيمة الوسيط top.

ترجمة -وبتصرف- للفصل Window sizes and scrolling من كتاب Browser: Document, Events, Interfaces


تفاعل الأعضاء

أفضل التعليقات

لا توجد أية تعليقات بعد



انضم إلى النقاش

يمكنك أن تنشر الآن وتسجل لاحقًا. إذا كان لديك حساب، فسجل الدخول الآن لتنشر باسم حسابك.

زائر
أضف تعليق

×   لقد أضفت محتوى بخط أو تنسيق مختلف.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   جرى استعادة المحتوى السابق..   امسح المحرر

×   You cannot paste images directly. Upload or insert images from URL.


×
×
  • أضف...