You built a clean navigation bar. The dropdown opens, the links look right, and then part of the menu hides behind a banner, a slider, or the next section on the page. You raise the z-index to 999, then 9999, and nothing changes. It feels like the browser is ignoring you completely.
This is one of the most common CSS frustrations for beginners and experienced developers alike. The good news is that z-index almost never breaks. Instead, a small condition around it stops it from applying. Once you know those conditions, you can fix a stubborn dropdown in a few minutes.
Quick Answer
z-index usually does not work because the element is not positioned. Add position: relative, position: absolute, or position: fixed to the dropdown, and give its parent a clear stacking order too. Also check for overflow: hidden on a parent and for a parent that creates its own stacking context, because both can trap or clip your menu no matter how high you set the number.
How Z-Index Actually Works
Think of your page as layers of paper on a desk. Elements that come later in the HTML often sit on top of earlier ones. z-index lets you change that order, but only inside a stacking context.
A stacking context is like a separate pile of papers. Inside one pile, you can reorder the sheets freely. But you cannot pull one sheet out and place it above a completely different pile if that pile itself sits lower. This is why a dropdown with z-index: 9999 can still lose to a header with z-index: 10. The numbers are not compared across the whole page. They are compared inside their own groups first.
The Position Rule You Cannot Skip
For most elements, z-index only works when the element has a position other than static. Static is the default, and it means the element simply follows the normal flow.
position: relativekeeps the element in the flow but lets you layer it.position: absoluteremoves it from the flow and positions it against its nearest positioned ancestor.position: fixedpositions it against the viewport.position: stickyalso responds toz-indexin modern browsers.
There is one helpful exception. Children of a flex or grid container can use z-index even without positioning. That exception helps sometimes, but relying on it makes debugging confusing. For a dropdown, explicit positioning is clearer and safer.
Step-by-Step Fix for a Dropdown Menu
Work through these steps in order. Most menus are fixed by step two or three.
- Select the dropdown panel itself, not just the link that opens it. This is usually a
ul, adivwith a menu class, or a panel inside a navigation item. - Add positioning to the parent list item. For example, use
.nav-item { position: relative; }so the panel has a stable anchor. - Add positioning to the dropdown. Use
.dropdown { position: absolute; top: 100%; left: 0; z-index: 1000; }so it sits below the parent and above page content. - Check the header or navigation wrapper. Give it
position: relativeand a reasonablez-indexsuch as100if it must sit above hero sections and sliders. - Remove or change any
overflow: hiddenon parents between the header and the dropdown. That property clips anything that extends beyond the parent box. - Reload the page and test on both desktop and mobile. Open and close the menu several times and scroll while it is open.
A Small Working Example
The pattern below solves the majority of cases. Notice that both the wrapper and the panel have positioning, and the numbers stay modest.
.site-header { position: relative; z-index: 100; }
.nav-item { position: relative; }
.dropdown { position: absolute; top: 100%; left: 0; z-index: 1000; background: white; }
You do not need extreme values like 999999. Clean, modest numbers are easier to maintain when you later add a modal, a cookie notice, or a mobile menu.
Five Hidden Reasons Your Menu Still Loses
1. A Parent Creates a Stacking Context
Many properties quietly create a new stacking context. Common triggers include transform, opacity below 1, filter, will-change, and isolation: isolate. Animations on a hero section are a frequent cause. If a parent has a transform for a fade-in effect, everything inside it is grouped together. Raising the child cannot lift it above an element outside that group. The fix is to raise the parent group itself, or move the dropdown markup outside the transformed container.
2. Overflow Is Clipping the Menu
If the menu is cut off in a clean straight line, suspect clipping before layering. A parent with overflow: hidden, overflow: auto, or overflow: scroll will hide the part of the dropdown that falls outside its box. This often happens on headers with a fixed height or on card containers. Change the overflow value, increase the parent height, or move the dropdown so it is a direct child of a container that does not clip it.
3. The Other Element Really Is Higher
Sticky headers, chat widgets, video players, and sliders often carry their own high values. Open your browser developer tools, select the element covering your menu, and read its position and z-index. Compare the stacking contexts, not just the raw numbers. If the covering element belongs to a higher context, you must raise your header context, not only the dropdown inside it.
4. The Dropdown Is Inside the Wrong Container
Component-based layouts sometimes place the menu inside a section that appears later or earlier in unexpected ways. If the dropdown lives inside a low section, it inherits that section’s limits. Moving the navigation to a proper header element near the top of the body, with its own positioning, removes a whole class of problems.
5. A Transform or Animation Keeps Running
Some sliders keep a transform applied even after an animation ends. That lingering transform keeps the stacking context alive. Check the computed styles in developer tools after the animation finishes. Removing the transform at the end of the animation, or applying the animation to an inner element instead, often frees the dropdown.
How to Debug It in Your Browser
Guessing wastes time. A short, systematic check finds the cause faster.
- Right-click the hidden part of the menu area and choose Inspect.
- Find the dropdown element in the HTML panel and confirm it is actually visible, with
displaynot set tononeat that moment. - Read its computed
positionvalue. If it saysstatic, you found the first problem. - Walk up through each parent in the HTML panel. Note any
transform,opacity,filter, oroverflowvalues. - Select the element that covers the menu and compare its ancestors with your menu’s ancestors until they meet. The first different ancestor is where you should compare
z-index.
This ancestor comparison is the key skill. For a deeper reference, the MDN guide to the z-index property explains stacking contexts with clear diagrams. Our guide to CSS position relative and absolute covers the positioning basics step by step.
Common Mistakes and Useful Tips
- Using huge numbers as a first fix: A value like 999999 hides the real cause and creates wars with modals later. Fix the context, then use small, planned numbers.
- Putting z-index on the wrong element: Adding it to the menu link does nothing for the panel. Apply it to the panel itself and to its wrapper.
- Forgetting the mobile menu: A desktop dropdown and a mobile drawer are different elements. Test both, because the mobile version often sits inside a different container.
- Ignoring sticky and fixed elements: Cookie bars and chat buttons are fixed and often carry high values. Plan a simple scale in advance, for example content 1 to 10, header 100, dropdown 1000, modal 2000.
- Leaving overflow hidden from a design shortcut: Developers often add it to stop horizontal scrolling. That is valid on the body in some cases, but dangerous on navigation wrappers.
- Not checking after animations load: Test the menu after sliders and popups have run, not only on a fresh, still page.
Keep a short layer scale in a comment at the top of your stylesheet. Shared scales prevent most stacking bugs.
Conclusion
When z-index seems to ignore you, the browser is usually following rules you have not spotted yet. Give the dropdown a real position, check its parents for stacking contexts and clipping, and compare ancestors instead of raw numbers. With that method, a menu that hides behind a banner becomes a five-minute fix rather than an afternoon of random guesses. Set a sensible layer scale, test on mobile and desktop, and your dropdown will stay confidently on top where visitors expect it.
Frequently Asked Questions
Why does z-index work on some elements but not on my dropdown?
Those other elements are probably positioned, or they are flex or grid children, which can use z-index without positioning. Your dropdown is likely still static, or it is trapped inside a parent stacking context with a lower order.
What z-index value should a dropdown menu use?
There is no magic number. A value between 100 and 1000 works well if your header context is already above page content. What matters is the order of the parent contexts, not making the number as large as possible.
Can overflow hidden break a dropdown even with a high z-index?
Yes. overflow: hidden clips content physically. It does not matter how high the layer is if a parent cuts it off at its border. Remove the clipping, enlarge the parent, or move the dropdown outside that parent.
Does transform affect z-index on a parent element?
Yes. A transform creates a new stacking context, so children are grouped inside it. Their z-index values only compete with siblings inside that group, not with elements elsewhere on the page.
Should I use !important to force my dropdown on top?
Almost never. !important on z-index does not fix positioning, clipping, or stacking context problems, which are the real causes in most cases. Fix the underlying structure instead, and your CSS will stay predictable as the site grows.


Leave a Reply