position: sticky not working
Sticky positioning has several gotchas.
Why this happens
position: sticky is a hybrid between relative and fixed β the element scrolls normally until it reaches a specified offset (like top: 0), then βsticksβ in place. It only works within its containing block (the nearest scrollable ancestor or the viewport). If any ancestor has overflow: hidden, overflow: auto, or overflow: scroll, the sticky elementβs scrollable area is limited to that ancestor, which often means it has no room to stick.
Fix 1: Add a top value
/* β Missing top */
.header { position: sticky; }
/* β
Must specify where to stick */
.header {
position: sticky;
top: 0;
}
Fix 2: Parent has overflow hidden
/* β overflow: hidden on any ancestor breaks sticky */
.parent { overflow: hidden; }
/* β
Remove overflow or use overflow: visible */
.parent { overflow: visible; }
Fix 3: Parent has no height
The sticky element needs room to scroll within its parent. If the parent is exactly the height of the sticky element, thereβs nowhere to stick.
Fix 4: Check all ancestors
Any ancestor with overflow: auto, overflow: scroll, or overflow: hidden can break sticky positioning.
Alternative solutions
If you canβt remove overflow: hidden from an ancestor (e.g., itβs needed to clip other content), use position: fixed instead and manage the layout offset manually:
.header {
position: fixed;
top: 0;
width: 100%;
z-index: 100;
}
body {
padding-top: 60px; /* offset for fixed header */
}
You can also use an IntersectionObserver in JavaScript to toggle a fixed class when the element reaches the top of the viewport.
Prevention
- When using
position: sticky, always include atop,bottom,left, orrightvalue β without it, the browser doesnβt know where to stick the element. - Avoid setting
overflow: hiddenon wrapper elements unless absolutely necessary, as it silently breaks sticky positioning for all descendants.
Related: CSS Flexbox Not Centering Β· CSS z-index Not Working Β· CSS Flexbox & Grid cheat sheet