Sticky header not staying on top problems usually happen when the header is missing a top value, trapped inside the wrong scroll container, placed behind content by z-index, or affected by overflow and stacking context rules.
Sticky Header Fix
Why is my sticky header not staying on top?
A sticky header can work for a few pixels, then disappear. It can stick inside the wrong parent, slide behind a hero section, or stop staying on top when another element creates a new stacking context. The fix is not just “add z-index.” You need to check the sticky offset, parent overflow, scroll container, and stacking order together.
- position sticky
- z-index
- overflow hidden
- stacking context
What the bug looks like
The header scrolls away, sticks only inside one section, sits behind content, or stops being clickable on mobile.
Why it happens
Sticky behavior depends on the nearest scroll container, the sticky offset, and the stacking context around the header.
What usually fixes it
Put the header high in the HTML, add a real top value, avoid trapping parent overflow, and use a deliberate z-index.
position:sticky is missing the sticky offset
position:sticky does not mean “always stay at the top.” It means the element behaves normally until it reaches a specified offset. Without top:0, the browser may have no useful sticky boundary.
Broken code
Missing top value.site-header {
position: sticky;
z-index: 10;
}Broken visual result
Correct code
Sticky offset added.site-header {
position: sticky;
top: 0;
z-index: 100;
}Fixed visual result
top:0 tells the browser the exact point where the header should become sticky.A parent with overflow is trapping the sticky header
Sticky elements stick relative to their nearest scrolling ancestor. If the header is inside a wrapper with overflow:hidden, overflow:auto, or a short height, the header may only stick inside that wrapper instead of the page.
Broken code
Overflow trap.page-shell {
height: 320px;
overflow: hidden;
}
.site-header {
position: sticky;
top: 0;
}Broken visual result
Correct code
Header outside overflow wrapper.site-header {
position: sticky;
top: 0;
z-index: 100;
}
.page-shell {
overflow: visible;
}Fixed visual result
The header is sticky, but it is behind other content
A header can stay at the top and still look broken if a hero, card, dropdown, or transformed section paints above it. In that case, the issue is stacking order, not sticky behavior.
Broken code
Low z-index.site-header {
position: sticky;
top: 0;
z-index: 1;
}
.hero-card {
position: relative;
z-index: 10;
}Broken visual result
This card paints above the sticky header because its z-index wins.
Correct code
Deliberate header layer.site-header {
position: sticky;
top: 0;
z-index: 1000;
}
.hero-card {
position: relative;
z-index: 1;
}Fixed visual result
The content keeps its layer, but the header has the higher page-level layer.
The sticky header is inside the wrong HTML structure
A site-wide sticky header should usually live near the top of the page structure, not inside a hero section, card, slider, or small wrapper. If its parent ends, the sticky behavior ends with it.
Broken code
Header nested too deep<section class="hero">
<header class="site-header">...</header>
<div class="hero-content">...</div>
</section>
<main>...</main>Broken visual result
Correct code
Header at page level<header class="site-header">...</header>
<main>
<section class="hero">...</section>
<section class="content">...</section>
</main>Fixed visual result
A production-minded sticky header pattern
A reliable sticky header pattern uses a page-level header, a clear sticky offset, a deliberate z-index layer, and avoids placing the header inside wrappers that create scroll or stacking traps.
Premium code
Sticky header system<header class="site-header">
<a class="logo" href="/">Brand</a>
<nav class="main-nav">...</nav>
</header>
<main class="site-main">
...
</main>:root {
--header-layer: 1000;
}
.site-header {
position: sticky;
top: 0;
z-index: var(--header-layer);
background: rgba(255,255,255,.96);
border-bottom: 1px solid #e5e7eb;
}
.site-main {
min-width: 0;
}
html {
scroll-padding-top: 80px;
}Premium visual result
Fast practical rule
If a sticky header is not staying on top, do not start by throwing bigger z-index values at it. First confirm top:0, then check parent overflow, then check whether another element created a stacking context above the header.
Debug checklist
- Check that the header has
position:stickyand a real offset liketop:0. - Inspect every parent of the header for
overflow:hidden,overflow:auto, oroverflow:scroll. - Move the header outside short wrappers, hero sections, sliders, and cards when it should stick for the whole page.
- Give the header a deliberate page-level z-index, such as
z-index:1000. - Check whether another element has a higher z-index than the header.
- Look for stacking context creators like
transform,filter,opacity,isolation, or positioned parents. - Test mobile breakpoints to make sure the header is not switched back to
position:static. - If anchor links hide under the header, add
scroll-padding-toporscroll-margin-top.
top:0. Sticky needs an offset to know when to stick.Final takeaway
A sticky header not staying on top is usually not one single CSS mistake. It is usually a combination of sticky offset, parent overflow, z-index, stacking context, and HTML structure.
Start with top:0, then inspect the parent containers, then fix the stacking order. Once the header is a clean page-level element with a deliberate layer, it becomes predictable on desktop and mobile.