حل مشكلة Z-Index في CSS: فهم ترتيب التكدس والسياق التكدسي
مقدمة إلى خاصية Z-Index في CSS
تُعد خاصية z-index في CSS من الخصائص القوية التي تتيح لنا التحكم في ترتيب العناصر المتراكبة على محور العمق (Z-axis). ومع ذلك، قد تبدو هذه الخاصية معقدة وغير فعالة في بعض الأحيان إذا لم يتم فهم آليتها بشكل صحيح. في هذا المقال، سنتعمق في شرح ماهية خاصية z-index، وكيفية عمل ترتيب التكدس (Stacking Order) والسياق التكدسي (Stacking Context)، وسنقدم حلولاً عملية لأكثر المشكلات شيوعاً التي قد تواجهك عند استخدامها.
ما هو Z-Index؟
يأتي الحرف Z في z-index من تمثيل الأبعاد الثلاثة: X و Y و Z. حيث يمثل المحوران X و Y العرض والارتفاع على التوالي، بينما يمثل البعد الثالث، Z، العمق. تخيل أنك تنظر إلى صفحة الويب من الأعلى، فالعناصر ذات العمق الأكبر تظهر أقرب إليك.

توفر CSS خاصية z-index لتمكيننا من تحديد عمق العنصر. كلما زادت قيمة z-index لعنصر ما، كلما ظهر في المقدمة أمام العناصر الأخرى على محور العمق. لننتقل إلى بعض الأمثلة لنرى كيفية استخدام z-index بالطريقة الصحيحة.
لماذا لا يعمل Z-Index بدون تحديد خاصية Position؟
أحد أهم الأمور التي يجب معرفتها هي أن كل عنصر على صفحة الويب له موضع افتراضي، وهو ما يُعرف بالموضع الثابت (position: static). لنفترض أن لدينا صندوقين، أحدهما أحمر والآخر أزرق، على صفحتنا:
<div class="box box-red"></div>
<div class="box box-blue"></div>

إذا قمت بتطبيق خاصية z-index مباشرة على هذين الصندوقين، ستلاحظ أنها لن تعمل. والسبب في ذلك هو أنهما لا يملكان موضعاً محدداً (position) بخلاف القيمة الافتراضية static:
.box {
height: 150px;
width: 150px;
}
.box-red {
background: red;
z-index: 1;
}
.box-blue {
background: #00d5f1;
bottom: 80px;
left: 55px;
z-index: 2;
}
هذا هو أحد الأمثلة الأكثر شيوعاً لعدم عمل z-index بشكل صحيح. لحل هذه المشكلة، يجب علينا تطبيق خاصية position بقيمة أخرى غير static (مثل relative أو absolute أو fixed أو sticky) على الفئة .box، وهذا سيجعل z-index فعالاً:
.box {
height: 150px;
width: 150px;
position: relative; /* تطبيق خاصية الموضع */
}

فهم ترتيب التكدس (Stacking Order)
حتى لو قمنا بإزالة خاصية z-index من الصندوقين، سيظل الصندوق الأزرق يظهر أمام الصندوق الأحمر، وهذا يرجع إلى وجود ترتيب افتراضي للعناصر على محور Z، يُعرف بترتيب التكدس. لننظر إلى هذا المثال:
.box {
height: 150px;
width: 150px;
position: relative;
}
.box-red {
background: red;
}
.box-blue {
background: #00d5f1;
bottom: 80px;
left: 55px;
}

عندما تكون جميع العناصر على نفس المستوى ولا يتم تطبيق z-index عليها، تستخدم المتصفحات ترتيب تكدس افتراضي لتحديد أي عنصر يظهر في المقدمة. هذا الترتيب هو كالتالي:
- خلفية وحدود العنصر الجذري (
<html>). - العناصر الفرعية غير المحددة الموضع (
position: static) بترتيب ظهورها في HTML. - العناصر الفرعية المحددة الموضع (
positionبقيمة أخرى غيرstatic) بترتيب ظهورها في HTML.
لاحظ أن العنصر الجذري يشير إلى العنصر <html>، بينما العناصر غير المحددة الموضع هي تلك التي لديها position: static الافتراضي، والعناصر المحددة الموضع هي تلك التي تم تعيين خاصية position لها على قيمة أخرى (مثل relative أو absolute).
مثال على تأثير ترتيب التكدس الافتراضي
إذا أضفنا صندوقاً آخر، ولكننا قمنا بتعيين خاصية position له على القيمة الافتراضية static، فسيظهر خلف الصندوقين الأزرق والأحمر المحددين الموضع:
<div class="box box-red">
<p>Positioned</p>
</div>
<div class="box box-blue">
<p>Positioned</p>
</div>
<div class="box box-yellow">
<p>Non-positioned</p>
</div>
.box {
height: 150px;
width: 150px;
position: absolute;
}
p {
color: #0a0a23;
margin: 0;
padding-left: 5px;
}
.box-red {
background: red;
top: 40px;
left: 27px;
}
.box-blue {
background: #00d5f1;
top: 80px;
left: 55px;
}
.box-yellow {
background: rgb(251, 239, 0);
position: static; /* صندوق غير محدد الموضع */
}

يوضح هذا المثال كيف أن العناصر المحددة الموضع (position: absolute في هذه الحالة) تظهر دائماً فوق العناصر غير المحددة الموضع (position: static) على نفس المستوى، وذلك بفضل ترتيب التكدس الافتراضي للمتصفح.
السياق التكدسي (Stacking Context): تأثير العنصر الأب على الأبناء
ماذا يحدث عندما لا تكون العناصر على نفس المستوى؟ لنفترض أننا وضعنا صندوقاً أصفر داخل الصندوق الأحمر، ثم وضعنا الصندوق الأزرق بجانبهما:
<div class="box box-red">
<div class="box box-yellow"></div>
</div>
<div class="box box-blue"></div>
.box-red {
background: red;
z-index: 1;
}
.box-blue {
background: #00d5f1;
bottom: 80px;
left: 55px;
z-index: 2;
}
.box-yellow {
background: rgb(251, 239, 0);
left: 25px;
top: 25px;
z-index: 3;
}

كما ترى في الكود، على الرغم من أن الصندوق الأصفر لديه قيمة z-index أعلى مقارنة بالصندوق الأزرق، إلا أنه يظهر خلف الصندوق الأزرق. هذا يحدث لأن الصندوق الأصفر هو ابن للصندوق الأحمر، وقيمة z-index للعنصر الأب تؤثر دائماً على أبنائه.
ببساطة، يتم إنشاء سياق تكدسي (Stacking Context) جديد عندما يكون لعنصر محدد الموضع (position غير static) قيمة z-index غير افتراضية (أي غير auto). في مثالنا، الصندوق الأحمر (بـ z-index: 1) ينشئ سياقاً تكدسياً جديداً لأبنائه. داخل هذا السياق، يعمل الصندوق الأحمر كعنصر جذري، والصندوق الأصفر هو عنصر محدد الموضع بداخله.
بما أن الصندوق الأزرق هو جزء من نفس السياق التكدسي للعنصر <html> (الذي يضم الصندوق الأحمر)، فإنه سيظهر دائماً فوق الصندوق الأصفر، لأن z-index للصندوق الأزرق (2) أعلى من z-index للصندوق الأحمر (1)، والذي بدوره يحدد مستوى تكدس الصندوق الأصفر.
يتكون السياق التكدسي من نفس قائمة ترتيب التكدس التي ذكرناها سابقاً:
- عنصر HTML جذري (أو العنصر الذي أنشأ السياق التكدسي).
- العناصر غير المحددة الموضع (
position: static) بترتيب ظهورها. - العناصر المحددة الموضع (
positionبقيمة أخرى) بترتيب ظهورها.
إذا واجهت هذا النوع من المشكلات، يمكنك حلها بإحدى طريقتين:
- إخراج العنصر الابن من العنصر الأب.
- إزالة خاصية
positionمن العنصر الأب بحيث لا تؤثرz-indexعلى أبنائه.
حل مشكلة السياق التكدسي
لنطبق الحل الأول بإخراج الصندوق الأصفر من الصندوق الأحمر:
<div class="box box-red"></div>
<div class="box box-yellow"></div>
<div class="box box-blue"></div>
.box {
height: 150px;
width: 150px;
position: relative;
}
.box-red {
background: red;
z-index: 1;
}
.box-blue {
background: #00d5f1;
bottom: 240px;
left: 55px;
z-index: 2;
}
.box-yellow {
background: rgb(251, 239, 0);
bottom: 120px;
left: 25px;
z-index: 3;
}

الآن، بعد أن أصبحت الصناديق الثلاثة على نفس المستوى من السياق التكدسي، تعمل خاصية z-index كما هو متوقع، ويظهر الصندوق الأصفر ذو القيمة الأعلى في المقدمة.
تجدر الإشارة إلى أن هناك عدداً من الخصائص الأخرى التي تؤثر على السياق التكدسي للعنصر، مثل opacity الأقل من 1، و transform، و filter، وغيرها. فهم هذه الخصائص أمر أساسي للتحكم الكامل في ترتيب العناصر.
تجنب تعيين أرقام كبيرة لـ Z-Index
أحد الأخطاء الشائعة الأخرى التي قد تؤدي إلى عدم عمل z-index كما هو متوقع هو تعيين أرقام كبيرة جداً لخاصية z-index، مثل 9999 أو 99999:
.box-blue {
z-index: 9999;
}
على الرغم من أن هذا قد يحل المشكلة مؤقتاً في بعض الحالات، إلا أنه يمثل ممارسة سيئة في تطوير الويب. تخيل أنك تعمل على مشروع كبير وتجد أن عنصراً ما لا يظهر في الترتيب الصحيح، وبعد البحث تكتشف أن أحدهم قام بتعيين قيمة z-index عالمية ضخمة (مثل 9999) لعنصر آخر، مما يتسبب في تجاوز أي قيم z-index تحاول تطبيقها.
هذه الممارسة تجعل إدارة ترتيب العناصر صعبة للغاية وتؤدي إلى تعقيدات غير ضرورية. بدلاً من ذلك، يجب استخدام قيم z-index صغيرة ومعقولة، مع فهم عميق لترتيب التكدس والسياق التكدسي، لضمان هيكلة واضحة وسهلة الصيانة لتصميمك.
الخلاصة التقنية
تُعد خاصية z-index أداة قوية في CSS لترتيب العناصر على محور العمق، ولكنها تتطلب فهماً دقيقاً لآلياتها. تكمن المشكلة الأساسية في كثير من الأحيان في عدم تحديد خاصية position للعنصر بقيمة غير static، أو في عدم فهم مفهوم السياق التكدسي وتأثير العنصر الأب على أبنائه. إن استخدام قيم z-index ضخمة هو حل سطحي يعكس نقصاً في الفهم العميق لتدفق التكدس، ويجب تجنبه لضمان قابلية الصيانة والمرونة في المشاريع الكبيرة. بتطبيق المبادئ الصحيحة لترتيب التكدس والسياق التكدسي، يمكن للمطورين التحكم بشكل كامل في تراكب العناصر وتحقيق التصميم المرغوب بكفاءة وفعالية.