Module 22 : Bootstrap Z-Index & Stacking Context.
why stacking order matters in web UI, how CSS stacking contexts and z-index work, and how to reason about and control stacking using Bootstrap-friendly approaches.
HTML structure, core CSS (positioning, display), Bootstrap basics (grid, components), and basic use of browser devtools.
What is z-index?
z-index is a CSS property that suggests the stacking order for elements within the same stacking context. Higher numeric values paint above lower ones. But z-index only applies to elements that are positioned (i.e., position is not static) except in some browsers where other rules apply; more importantly, it cannot transcend stacking contexts.
What is a Stacking Context?
A stacking context is an isolated group where elements are stacked in a specific order. Think of each stacking context as a separate canvas: z-index values are only comparable for elements inside the same canvas. If an element forms a new stacking context, all of its children will be stacked within it first; that whole group is then placed within the parent stacking context according to the group's own position.
Important implication: A child with a very large z-index cannot escape and appear above an ancestor's sibling if its ancestor itself is lower in the parent's stacking context.
Common Triggers that Create a New Stacking Context
An element becomes a stacking context when any of the following (non-exhaustive) conditions are met:
Root element (the document root) — the top stacking context.
A positioned element (e.g., position: relative/absolute/fixed/sticky) with a z-index value other than auto.
opacity less than 1 (e.g., opacity: 0.99 creates a context).
transform other than none (e.g., transform: translateZ(0)), filter, perspective.
mix-blend-mode other than normal.
isolation: isolate.
will-change with certain values (can create stacking contexts when used).
These triggers may evolve in spec and implementations; always test suspicious cases in the target browser matrix.
The Painting Order
Within a stacking context, the painting order is something like:
Background and borders of the element forming the stacking context.
Descendants with negative z-index.
In-flow, non-positioned blocks.
Positioned elements with z-index: auto.
Descendants with z-index >= 0 in increasing order.
This is a simplification—consult the spec for formal ordering—but it is enough to reason about most bugs.
Bootstrap-Focused Methods:
1) The Safe Layering Strategy
Reserve a small z-index scale for global components: header, dropdowns, overlays, modals, tooltips.
Use CSS/SASS variables (or Bootstrap vars) to define named layers like --z-header, --z-dropdown, --z-modal rather than arbitrary numbers sprinkled across components.
Ensure components that must overlay everything (modals, backdrops) are attached to a top-level container (e.g., body or a designated portal element) to avoid being trapped in nested stacking contexts.
Why this works: Attaching overlays to the body avoids accidental parent stacking contexts, while named variables make audits and debugging easier.
2) Bootstrap Component Tips
Dropdowns & popovers: Ensure they are appended to a top-level container (many Bootstrap deployments provide an option to append to body). If your dropdown sports odd overlap issues with sticky headers or transforms, check whether any ancestor created a stacking context.
Modals and offcanvas: Always render them in a portal (outside regular document flow). Use a high global layer variable for modals and backdrops.
Sticky headers: position: sticky can form contexts when combined with transforms; test interactions with floating menus.
Tooltips: Keep small z-index values within the tooltip group, but ensure the tooltip's container is outside problematic stacking contexts.
3) When to Use transform: translateZ(0) or will-change
These are useful to trigger GPU compositing for performance but they can also create stacking contexts. Use them carefully — don't accidentally trap overlay elements.
4) Creating a Custom z-index Scale (SASS)
This is a conceptual SASS snippet you can include in your Bootstrap build system:
// _z-index.scss (conceptual)
$z-index-scale: (
'base' : 0,
'dropdown': 1000,
'sticky' : 1020,
'fixed' : 1030,
'modal' : 1050,
'toast' : 1080,
);
@function z($name) {
@return map-get($z-index-scale, $name);
}
// Example usage
.header { z-index: z('sticky'); position: sticky; top: 0; }
.modal-backdrop { z-index: z('modal') - 10; }
.modal { z-index: z('modal'); }
This keeps your layering predictable and centralized.
Examples
Example 1 — Dropdown behind sticky header
Problem: A dropdown menu appears behind a sticky header even though it has a larger z-index.
Cause: A parent of the header or the dropdown created a stacking context, and the dropdown is inside that context while the header's stacking context sits above it. The large z-index on the dropdown only applies inside its local stacking context.
Fix strategies:
Move/append the dropdown's container to the body (a portal).
Ensure the header's parent is not creating an unnecessary stacking context (check transform, opacity, isolation).
Use a centralized z-index scale and make sure the dropdown's stacking context is at the right level.
Code (illustrative):
<header class="site-header" style="position:sticky; top:0; z-index: 1000;">
Header
</header>
<div class="container">
<!-- If container has 'transform: translateZ(0)' or opacity < 1, it may create stacking context -->
<div class="dropdown" style="position: relative;">
<button class="btn">Open</button>
<div class="menu" style="position:absolute; z-index:2000">Menu</div>
</div>
</div>
If .container creates a stacking context above the header, the .menu will be trapped and cannot appear above the header.
Example 2 — Modal trapped by parent with transform
If a parent wrapper uses transform, modals placed inside that wrapper will be clipped or appear below other top-level UI. Always render critical overlays outside transformed parents.
Example 3 — opacity trapping child
A parent with opacity: 0.95 creates a stacking context; a child with high z-index cannot escape. Double-check any parent with opacity used for subtle visual effects.
Checklist
Inspect element in devtools. Look for transform, opacity, filter, position, isolation, will-change on ancestors.
Temporarily remove suspicious CSS (e.g., disable transform) to see if the bug disappears.
Reparent the overlay to body and test — if it fixes the issue, you found a stacking context trap.
Use computed styles to check the z-index values and stacking contexts (some browsers label stacking contexts in the elements panel).
Use outline borders to visualize which elements are overlapping and which stacking contexts they are in.
Exercises
Exercise 1 — Fix the dropdown
Create a page with a sticky header and a dropdown inside a transformed container that currently appears behind the header. Fix it without changing the header's z-index.
steps / solution:
Recreate scenario: make a wrapper with transform: translateZ(0) containing the dropdown.
Solution A (recommended): Move the dropdown’s menu to body (append or portal) and position it with JS/CSS.
Solution B: Remove the transform from the wrapper if possible.
Solution C: If you must keep the transform, ensure the header is in a higher stacking context and that the dropdown is reparented.
Why moving to body works: It places the dropdown in a different (higher) stacking context where it can be compared to the header's z-index directly.
Exercise 2 — Modal overlay gets clipped
A fixed modal seems clipped by a container with overflow: hidden. Find and fix.
Solution: overflow can clip child even if position: fixed. Place the modal container outside the clipping ancestor (e.g., append to body) or change the overflow strategy.
Exercise 3 — Build a z-index scale
Create a SASS map of z-index layers for a site
No comments:
Post a Comment