رأينا في الدرس السابق أكثر ثلاثة أنماط شيوعًا لتحديد مواقع العناصر في صفحات HTML عبر CSS، وهي static و relative و absolute. سننظر في هذا الدرس إلى fixed
و sticky
، ثم سنناقش طريقة ترتيب العناصر فوق بعضها عبر z-index
.
طريقة fixed لتحديد مواقع العناصر
هنالك قاعدة background-attachment: fixed
تُطبَّق على صور الخلفية، وأيضًا توجد قاعدة position: fixed
التي تُطبَّق على العناصر؛ حيث تسمح بأن يكون موقع العنصر ثابتًا نسبةً إلى الصفحة، مما يسمح بتمرير بقية العناصر مع بقاء العنصر في مكانه. ويُطبَّق ذلك عادةً على حاويات، فمن الأمثلة الشائعة هي الترويسات والتذييلات الثابتة. وكما عند ضبط العناصر ذات القاعدة position: absolute
، ستُصبِح جميع العناصر ذات القاعدة position: static
تحت أيّة محتوى له القاعدة position: fixed
.
هذه شيفرة HTML لعنصر ثابت يظهر على يسار الصفحة:
<div id="fixed-pull-tab"> <img src="red-tab.png" style="float: right" alt="LEVI’S"> <p>This is an example of an element with <code>position: fixed;</code> applied to it, for this blog’s article on the CSS property. </div>
استخدمتُ الخاصية box-shadow
في CSS على الصورة لكي أوضِّح أنَّ الحاوية موجودة في «طبقة» تعلو بقية المستند:
div#fixed-pull-tab { width: 300px; border: 1px solid #000; padding-left: 1em; background-color: rgba(255, 255, 37, 0.7); position: fixed; left: -265px; top: 200px; } div#fixed-pull-tab p { margin-right: 70px; } div#fixed-pull-tab img { box-shadow: 4px 4px 4px rgba(0, 0, 0, 0.33); } div#fixed-pull-tab:hover { left: 0; }
وكما في position: absolute
، يجب أن تُستخدَم القيمة fixed
بحذر، حيث تسمح هذه الخاصية بإنشاء عناصر في صفحات الويب التي تتداخل مع غيرها من محتوى الصفحة أو تغطي عليها.
حالة خاصة: العناصر الثابتة الموجودة داخل حاوية
في الحالات العادية، سيُزال العنصر المُطبَّق عليه القاعدة position: fixed
من المستند، وأيّة معلومات تُحدِّد مكانه نسبةً إلى العنصر <body>
ستصبح غير متاحة.
لكن، من الممكن وضع عنصر مُطبَّق عليه القاعدة position: fixed
داخل عنصر آخر ومنسوبًا إليه، وذلك إذا أُجري CSS transform عليه. فلو كانت لدينا الشيفرة الآتية:
<div id="container"> <div id="fixed"></div> </div>
يمكن أن يصبح العنصر الداخلي «ثابتًا» بالنسبة إلى العنصر الأب باستخدام شيفرة CSS الآتية (دون السابقات الخاصة بالمتصفحات، لغرض وضوح الشيفرة):
#container {
transform: translateZ(0);
}
#fixed {
position: fixed;
}
هذه «الميزة» الغربية هي جزء من مواصفات CSS، وهي مدعومة في جميع المتصفحات الحديثة التي جربتها (باستثناء IE 11)، وحسب معلوماتي، أول من اكتشف ذلك هو Eric Meyer، وأتوقع أنَّ هذه الميزة نادرة الاستخدام (أغلبية المطورين يفضلون استخدام absolute
مع relative
) لكن لا ضير من معرفة هذه المعلومة.
طريقة sticky لتحديد مواقع العناصر
مرت فترةٌ أصبحت فيها العناصر «الثابتة ديناميكيًا» هي ميزة التصميم الأساسية في الموقع، فإذا مرّرتَ إلى الأسفل فسيتحرك كل شيءٍ كما هو متوقع، لكن عندما يبلغ عنصرٌ معيّن (عادةً يكون شريط القائمة، أو إعلان في بعض الأحيان) أعلى الصفحة فسيثبت مكانه، بينما ستستمر بقية عناصر المستند بالتمرير أدناه؛ وعند التمرير إلى الأعلى فسيربط العنصر نفسه مرةً أخرى بالمستند.
هذا السلوك (الذي هو دمجٌ بين position: static
و position: fixed
) كان يُضاف إلى الصفحة باستخدام jQuery (عبر إحدى الإضافات الكثيرة الموجودة لهذا الغرض). وكالعديد من الميزات المشهورة، سينتهي بهذا الأمر إلى أن يصبح جزءًا من المواصفة الرسمية، مما يعني أننا سنتمكن من فعل ذلك باستخدام CSS بمفردها، دون إطارات عمل، أو سكربتات، أو غير ذلك… لكن في هذه الحالة، كانت (وما زالت) عملية التحويل إلى مواصفة مليئةً بالمشاكل.
كيف كان يُفتَرض لهذه الميزة أن تعمل
كنّا نكتب هذه الميزة كقيمة جديدة: position: sticky
، وذلك مع استخدامٍ ذكيٍ للخاصية top
(وهي ترمز عند استخدامها مع sticky
إلى المسافة من أعلى العنصر bodyالذي بعدها سيصبح العنصر «ثابتًا» عند التمرير؛ البدائل هي الخاصيات
leftو
bottomو
right` للتمرير في تلك الاتجاهات)، وكان ذلك كافيًا لتغطية طيفٍ واسعٍ من حالات الاستخدام؛ وبهذا ستصبح طريقة الاستخدام سهلةً جدًا:
#stickytest { position: sticky; top: 0px; }
وعند تطبيق ما سبق على صورة (مثلًا)، فستبدو الشيفرة كما يلي:
<img src="geckofoot.jpg" alt id="stickytest"> <p>Lorem ipsum…
ملاحظة: افتراضنا أنَّ الصفحة تحتوي على محتوى بعد العنصر لكي يصبح العنصر #stickytest
في أعلى نافذة المتصفح، وإذا لم تكن تحتوي الصفحة على عناصر أخرى، فلن يصل العنصر إلى المكان اللازم لكي «يثبت» مكانه. أنصحك بتعبئة الصفحة بكثير من النصوص لغرض التجربة.
إذا جربتَ الشيفرة السابقة على نسخةٍ حديثةٍ من متصفح Firefox، فيجب أن تعمل عملًا صحيحًا. لكن عند الانتقال إلى بقية المتصفحات، فسنجد أمورًا عجيبة!
1. متصفح Safari 6.1+ (على الحاسوب وعلى الهاتف) يدعم القيمة sticky
عبر سابقة (prefix) خاصة به. صحيحٌ أنَّ من غير الشائع أن تُطبَّق السابقة على القيمة، وليس على الخاصية.
2. هنالك أمرٌ بسيطٌ عليك الانتباه إليه ألا وهو أنَّ خاصية sticky
في Safari تعمل إذا كانت العناصر لها القاعدة display: block
، لذا يجب تعديل مثال الصورة السابق ليصبح:
#stickytest { display: block; position: -webkit-sticky; position: sticky; top: 0px; }
بالإضافة إلى:
-
وضع عنصر
sticky
داخل حاوية لها القاعدةoverflow: hidden
سيؤدي إلى عدم تطبيق سلوكsticky
. -
رسميًا، يجب أن يعمل
sticky
معdisplay: table
، بما في ذلك خلايا الجدول، وهذا مفيدٌ عند التنقل في الجداول الطويلة مع إبقاء عناوين الأعمدة ظاهرةً. لكن للأسف لم تُطبَّق هذه الميزة في المتصفح.
متصفح Chrome ينسحب من السباق
ربما تجد في الويب بعض الصفحات التي تُصّر أنَّ متصفح Chrome يدعم القاعدة position: sticky
كخيارٍ اختباري، وكان هذا صحيحًا… إلى أن أُلغي هذا الخيار تمامًا في Chrome 37. شعر فريق تطوير Google أنَّ إبقاء position: sticky
هو تحدٍ لهم في مسعاهم في تحسين سرعة العرض في المتصفح، لهذا ألغيت هذه الميزة. وهذا يعني أنَّ علينا العودة إلى الطرق الالتفافية لإنشاء هذا السلوك في متصفح Chrome و Internet Explorer (الذي لم يدعم القيمة الجديدة قط).
لحسن الحظ، هنالك بعض الخيارات المتاحة أمامنا: فلدى Filament Group حلٌّ يعتمد على jQuery، بالإضافة إلى غيره من الحلول. أفضِّل -شخصيًا- استخدام stickyfill من تطوير Oleg Korsunsky، والذي يمكن أن يعمل مع أو بدون jQuery.
المثال الموجود في صفحة StickFill يُضيف سلوك sticky كفئة CSS، لكن من المرجَّح أن تُطبِّق ذلك على عنصرٍ وحيد، وإنشاء مُحدِّد يعتمد على المُعرِّف id
هو أمرٌ منطقي. وفي هذا المثال، سأضيف إلى السكربت الموجود أسفل الصفحة السطرَ الآتي:
Stickyfill.add(document.getElementById('stickytest'));
لاحظ أنَّ قيم top
و left
و bottom
و right
للعنصر مُقاسةٌ من العنصر body
، وهذا يتضمن أيّة هوامش موجودة للعنصر body
.
أبقِ الأمر بسيطًا
صحيحٌ أنَّ position: sticky
لها العديد من الميزات، لكن تسهل إساءة استخدامها. ولتفادي الكوارث التي تتعلق بواجهة المستخدم فسأنصحك باتباع ما يلي:
- نظريًا، يمكن استخدام position: sticky
لإبقاء العناصر ثابتةً داخل أيّ حاوية قابلة للتمرير، كما في هذا المثال؛ لكن رجاءً لا تستخدمها في أكثر من مكان في الصفحة، فلا نحتاج إلى ذلك! (إضافةً إلى أنَّ جميع الحلول الالتفافية المتوافرة لقاعدة position: sticky
ستفشل في توفير هذه الميزة، وسيعمل المثال السابق في حاويةٍ في الصفحة لأنها تلك الحاوية عبارة عن عنصر iframe
).
- كن حذرًا للغاية عند استخدام position: sticky
على شاشات الهاتف المحمول: فكل شيءٍ سيثبت مكانه سيأخذ مساحةً كبيرةً من الشاشة، مما يقلّل من المساحة الباقية لعرض محتواك. يجب أن تضبط العنصر ليكون ثابتًا sticky
إذا كان ذلك ضروريًا جدًا أو كان مفيدًا للغاية، وليس لأنه «يبدو بشكلٍ جميل». تذكّر أنَّه من الأسهل للمستخدمين أن يُمرِّروا في الصفحة باللمس أعلى أو أسفل الشاشة، لذا لا تقف بطريقهم!
لضمان استخدام sticky
استخدامًا حكيمًا، فاكتب قاعدة @media
التي تبطل تأثير position: sticky
على الشاشات الصغيرة:
@media all and (max-width: 600px) { #stickytest { position: static !important; } }
ما سبق سيُعيد العنصر إلى مكانه الطبيعي في المستند إذا كان عرض الشاشة 600 بكسل أو أقل. ستحتاج إلى كتابة قاعدة مشابهة في JavaScript باستخدام matchMedia
إذا كنتَ تستعمل حلًا التفافيًا. أعد كتابة السكربت أعلاه إلى شيءٍ شبيهٍ بما يلي:
var sticky = document.getElementById('stickytest'); var screencheck = window.matchMedia("(max-width: 600px)"); Stickyfill.add(sticky); if (screencheck.matches) { Stickyfill.remove(sticky); }
- كقاعدة عامة، يجب أن تكون العناصر «الثابتة» هي نقطة لانقطاع المحتوى، فلا «تُثبِّت» العناصر في منتصف قطعة من المحتوى، مما يجعل النص يظهر أعلى وأسفل العنصر الثابت، وهذا أمرٌ يُشتِّت القارئ كثيرًا، ويُصعِّب من قراءة النص.
- وشبيهًا بما سبق، حاول أن تتفادى تثبيت العناصر التي تقسم جزءًا من محتوى نصي، مما يجبر المستخدم على التمرير بسرعة أبطأ لقراءة السطر بأكمله.
- احرص أنَّ لا تحتل العناصر الثابتة أكثر من الحد الأدنى المتوقع لنافذة المتصفح، فلو كانت أطول من حاويتها فلن يتمكن المستخدمون من رؤية كامل محتواها ولن يستطيعوا أيضًا قراءة بقية المحتوى الموجود في الصفحة.
-
إضافةً إلى ما سبق، ربما تريد أن تُشير إلى أنَّ المحتوى تحت العنصر الثابت سيكون مخفيًا، وربما تستعمل تأثير الشفافية مثلًا عندما يُثبَّت العنصر، كتأثير عدم الوضوح على المحتوى خلف شريط الانتقال.
فكرة أخرى هي تطبيق القاعدةposition: sticky
على سلسلة من العناصر، مما يجعلها تظهر بعضها تلو بعض عند نقاط مُحدِّدة أثناء التمرير. وعلى الرغم من أنَّ هذه الطريقة قد تكون فعالة، لكن يُحتَمَل أن تُربِك المستخدمين، لذا نفِّذها بعد أخذ الحيطة.
للأسف، لا يوجد حدث باسمstuck
في JavaScript للتبليغ أنَّ أحد العناصر قد أصبح بموضعٍ ثابتٍ. لكن يمكنك الآن اختبار ذلك يدويًا (بعض الطرائق الالتفافية تستخدم فئةclass
خاصة بالعناصر الثابتة للتعويض عن عدم وجود الحدثstuck
).
ترتيب العناصر فوق بعضها عبر z-index
عندما توضع العناصر في الصفحة بمكانٍ مطلق (absolute
) فيمكن أن تتداخل وتغطي على المحتوى العادي، وعلى بقية العناصر التي لها القاعدة position: absolute
أيضًا. لكن عندما يحدث ذلك، فكيف سيُحدِّد المتصفح ما هو العنصر الذي يجب أن يكون في الأعلى؟
افتراضيًا، يُحدِّد المتصفح ترتيب العناصر فوق بعضها عبر ترتيب ورودها في الشيفرة. أفضل طريقة لتصور ذلك هي تخيل مجموعة أوراق لعب، وبعض أوراقها موزعةٌ على الطاولة، وتلك الأوراق هي المحتوى العادي للصفحة بما في ذلك العناصر ذات القيمة static
و relative
و fixed
. وإذا تداخلت مع أوراقٍ أخرى موضوعة مسبقًا على الطاولة (وتلك هي العناصر ذات القيمة absolute
)، فسيتم ترتيب الأوراق بناءً على ترتيب سحبها (أي أنَّ العناصر الحديثة ستظهر فوق العناصر الأقدم…). ففي مثالنا في الدرس السابق [أضف رابط درس 34676-CSS-Positioning-static-relative-absolute]، ظهرت الصور بترتيبٍ معيّن في الشيفرة، فعندما تداخلت الصور كانت صورة إسخيلوس في أسفل المجموعة، ثم أفلاطون فوقها، وفي الأعلى صورة ألكيبيادس. أسهل طريقة لإنشاء «طبقات» لعناصر ذات القاعدة position: absolute
هي تغيير ترتيب ورودها في الشيفرة، فمثلًا لو غيرنا الشيفرة إلى:
<div id="greek-figures"> <img src="plato-bust.jpg" alt="Plato" id="plato"> <img src="aeschylus-bust.jpg" alt="Aeschylus" id="aeschylus"> <img src="alcibiades-bust.jpg" alt="Alcibiades" id="alcibiades"> </div>
فستنتج الصورة الآتية: صورة أفلاطون في المنتصف تحت الصورتين الأخريتين، لأنها تأتي أولًا في الشيفرة. ستبقى الصورة في نفس المكان، لكن ترتيبها قد تغيّر.
لأسبابٍ مختلفة، قد لا نستطيع تغيير ترتيب العناصر في الشيفرة (أو لا نرغب في ذلك) لكننا نريد ترتيب العناصر بترتيبٍ يختلف عن تسلسل ورودها في الشيفرة. سنُعيد الشيفرة إلى حالتها الأصلية:
<div id="greek-figures"> <img src="aeschylus-bust.jpg" alt="Aeschylus" id="aeschylus"> <img src="plato-bust.jpg" alt="Plato" id="plato"> <img src="alcibiades-bust.jpg" alt="Alcibiades" id="alcibiades"> </div>
إذا أردنا إعادة ترتيب العناصر، لكننا لا نريد تعديل الشيفرة، فيمكننا إضافة الخاصية z-index
إلى أنماط CSS التي تتحكم في الصور:
body p { text-align: justify; } div#greek-figures { float: right; width: 250px; height: 450px; margin-left: 2em; } div#greek-figures img { height: 150px; width: 150px; position: absolute; } img#aeschylus { z-index: 2; } img#plato { top: 155px; right: 15px; z-index: 1; } img#alcibiades { top: 290px; z-index: 2; }
الشيفرة السابقة ستؤدي إلى إظهار نفس نتيجة المثال الأول، لكن بدون الحاجة إلى تغيير شيفرة HTML.
تُعتَبَر قيمة الخاصية z-index
للعنصر body
هي 0
، وأيّة قيمة موجبة للخاصية z-index
لأي عنصر آخر ستجعله يظهر فوق العنصر <body>
. العناصر ذات الخاصية z-index
والمسند إليها قيمةٌ سالبةٌ ستكون أسفله. انتبه أنَّه لو كان للعنصر body
لون خلفية (عبر خاصية background-color
) فستختفي تلك العناصر تحته.
ما هو أعلى رقم يمكن إسناده للخاصية z-index
القيمة العظمى للخاصية z-index هي 2147483647 في المتصفحات الحديثة. من المستحيل أن يكون لديك أكثر من مليارَي عنصر مكدس فوق بعضه في الصفحة، لذا لا تحاول استخدام هذا الرقم عند كتابة شيفرات CSS.
ترجمة –وبتصرّف– لكل من:
CSS Positioning: fixed
position sticky: scroll-to-top-then-fixed in pure CSS
Stacking order and z-index
لصاحبها Dudley Storey
أفضل التعليقات
لا توجد أية تعليقات بعد
انضم إلى النقاش
يمكنك أن تنشر الآن وتسجل لاحقًا. إذا كان لديك حساب، فسجل الدخول الآن لتنشر باسم حسابك.