Files
hermes-config/skills/software-development/systematic-debugging/references/css-z-index-overflow-clipping.md
T
2026-07-12 10:17:17 -04:00

4.6 KiB

CSS Z-Index & Overflow Clipping Debugging

Symptom

A dropdown, tooltip, or popup renders but is cut off / hidden behind elements below it.

Root Cause (almost always one of these)

  1. Parent overflow: hidden — the dropdown's parent container clips it via CSS overflow
  2. Missing or broken z-index — the dropdown has no z-index, or its z-index CSS variable is undefined
  3. Stacking context — a parent creates a new stacking context (via position: relative + z-index, opacity < 1, transform, filter, will-change) which limits how high the child can stack
  4. Parent position / overflow conflictsposition: relative on a grandparent with overflow: hidden blocks absolute children even with high z-index
  5. Sibling DOM ordering — the header wrapper has no z-index, so its sibling (main content) paints on top by default

Diagnosis Checklist

1. Check parent overflow

# Search for overflow:hidden on or near the dropdown's container
search_files("overflow-hidden", file_glob="*.html", path="src/")
search_files("overflow-hidden", file_glob="*.css", path="src/")
search_files("overflow.*hidden", file_glob="*.html", path="src/")

2. Check CSS variable definitions

# If the dropdown uses a CSS variable for z-index, verify it's defined
# e.g., `z-index: var(--z-critical) !important;` without `--z-critical: N;` in :root = broken
search_files("--z-", file_glob="*.css", path="src/")
search_files("var\(--z-", file_glob="*.html", path="src/")
search_files("var\(--z-", file_glob="*.js", path="src/")

A CSS variable referenced but never defined evaluates to z-index: invalid — effectively no z-index at all.

3. Check the element's actual z-index

In browser dev tools: inspect the dropdown → computed styles → z-index. If it says invalid or isn't listed, the variable isn't resolving.

4. Check the outer wrapper's position and z-index

Even when the dropdown and its immediate parent have high z-index, the outermost header wrapper may lack position: relative, allowing the next DOM sibling (main content) to paint on top.

Check: Does the <div> that wraps the entire header have position: relative and z-index?

Fixes

Fix 1: Ensure parent overflow is visible

On the dropdown's immediate positioned parent:

overflow: visible !important;

Or remove overflow-hidden from the Tailwind class list if overflow-visible-important is already applied.

Fix 2: Define undefined CSS variables

:root {
    --z-critical: 999999;
}

Fix 3: Set z-index on the header card

.header-card {
    z-index: 100;
    position: relative;
}

This keeps the header above page content, so the dropdown (which is a child) can stack above content below the header.

Fix 4: Remove conflicting Tailwind classes

If a div has both overflow-hidden AND a class that sets overflow: visible !important, remove overflow-hidden — the !important should win in theory, but mobile Safari and some browsers handle this inconsistently.

Fix 5: Set z-index on the outer header wrapper (non-obvious)

Even with Fix 1-4, the dropdown can be covered by page content. This happens when the outermost header div doesn't create a stacking context:

<div class="header-wrapper">           ← NEEDS position:relative + z-index
  <div class="header-card z-100">      ← Fix 3 applied
    <div id="user-dropdown" z-10001>   ← high z-index
  </div>
</div>

<div class="main-content">             ← SIBLING of header-wrapper
  ...                                  ← paints ON TOP without Fix 5
</div>

Fix: Add position: relative; z-index: 1000; to the outermost header wrapper div (not just the header-card inside it). A value of 1000 is enough to beat any content z-index below.

Multi-Layer Verification

After fixing, check ALL pages that share the same component:

  • Search for the same CSS classes/IDs across all HTML files
  • Check if each page has its own <style> block that overrides the shared stylesheet
  • Verify that shared stylesheet changes (e.g., style.css) apply to all pages

Common Pattern: Header Dropdown Clipping

<div class="header-card overflow-hidden">   ← PROBLEM: clips children
  <div class="user-menu-container relative">
    <div id="user-dropdown">...</div>       ← gets clipped
  </div>
</div>

Fix: Remove overflow-hidden from header-card, add z-index to it, and ensure the dropdown has a defined high z-index. Add .user-menu-container { overflow: visible !important; } for safety. Then add position: relative; z-index: 1000 to the outer header wrapper to beat sibling DOM ordering.