Z-index و Stacking Context — تصميم CSS
z-index وسياق التراكب
عندما تتداخل العناصر (بسبب position أو هوامش سالبة أو transform)، أيها يظهر فوق؟
الترتيب الافتراضي
بلا z-index: العنصر الذي يأتي لاحقاً في HTML يظهر فوق، والعناصر المُموضَعة فوق غير المُموضَعة.
z-index
.dropdown {
position: absolute;
z-index: 10; /* أعلى = أقرب للمستخدم */
}- يعمل مع العناصر المُموضَعة (relative و absolute و fixed و sticky)، ومع عناصر Flex و Grid الأبناء.
- على عنصر static لا أثر له — أول ما تفحصه عندما "لا يعمل z-index".
- يقبل أرقاماً سالبة (خلف الأب في بعض الحالات).
سياق التراكب: سبب أغلب المشاكل
بعض الخصائص تنشئ سياق تراكب جديداً: مجموعة مغلقة تُرتَّب طبقاتها داخلياً، ثم تُعامل كطبقة واحدة مع ما حولها.
<div class="header"> <!-- position: relative; z-index: 1 -->
<div class="menu">قائمة</div> <!-- z-index: 9999 -->
</div>
<main class="content">محتوى</main> <!-- position: relative; z-index: 2 -->القائمة ستظهر تحت المحتوى رغم 9999! لأنها محبوسة داخل سياق .header (قيمته 1)، و .content قيمته 2. لا رقم داخل الصندوق يخرجه من صندوقه.
ما الذي ينشئ سياق تراكب؟
- position غير static مع z-index غير auto.
- position: fixed أو sticky.
- opacity أقل من 1.
- transform أو filter أو perspective بأي قيمة غير none.
- عنصر Flex/Grid ابن بـ z-index غير auto.
- isolation: isolate (لإنشائه عمداً).
طريقة التشخيص
1. هل العنصر مُموضَع؟ إن لم يكن، z-index لا يعمل.
2. اصعد في الآباء: من منهم ينشئ سياق تراكب؟ (transform و opacity مشتبهان معتادان.)
3. قارن قيم z-index بين الأشقاء على نفس المستوى، لا بين عناصر في صناديق مختلفة.
4. الحل غالباً: ارفع z-index على الأب المشترك، أو انقل العنصر (النوافذ المنبثقة توضع عادة كابن مباشر لـ body).
نظام قيم ثابت
بدل أرقام عشوائية (999، 9999، 99999...) عرّف سلّماً واحداً في متغيرات:
:root {
--z-dropdown: 100;
--z-sticky: 200;
--z-overlay: 300;
--z-modal: 400;
--z-toast: 500;
}
.modal { position: fixed; z-index: var(--z-modal); }isolation: isolate
لمكوّن (بطاقة مثلاً) يستخدم z-index داخلياً، isolation: isolate يحبس طبقاته داخله فلا تتصادم مع بقية الصفحة.
تمرين
أنشئ رأساً sticky وقائمة منسدلة داخله، ثم بطاقة تحته فيها transform: translateY(-4px) عند المرور. هل تختفي القائمة خلف البطاقة؟ شخّص المشكلة بالخطوات أعلاه وأصلحها.
/* نظام طبقات منظم */
:root {
--z-dropdown: 100;
--z-sticky: 200;
--z-fixed: 300;
--z-modal-backdrop: 400;
--z-modal: 500;
--z-popover: 600;
--z-tooltip: 700;
}
.dropdown-menu {
position: absolute;
z-index: var(--z-dropdown);
}
.sticky-header {
position: sticky;
top: 0;
z-index: var(--z-sticky);
}
.modal-backdrop {
position: fixed;
inset: 0;
background: rgba(0,0,0,0.5);
z-index: var(--z-modal-backdrop);
}
.modal {
position: fixed;
z-index: var(--z-modal);
}
.tooltip {
position: absolute;
z-index: var(--z-tooltip);
}اختبر فهمك