Usage
<div data-sticky-root>
<div class="sticky theme container" data-sticky>
<h2 style="text-align: center">Sticky Header</h2>
</div>
<div>
<div class="l-stack">
<div style="min-height: 200vh">
<h2>Start Scrolling</h2>
</div>
</div>
</div>
</div>
html {
scroll-padding-top: 100px;
scroll-behavior: smooth;
}
.sticky {
position: sticky;
top: 0;
left: 0;
transition: transform 400ms ease-in;
transform: translateY(0);
z-index: 2;
}
export default class StickyHeader {
stickyClass = '-is-stuck';
constructor(stickyElement) {
this.stickyElement = stickyElement;
this.previousScrollYPos = window.scrollY;
document.addEventListener("scroll", this.scrollListener.bind(this), { passive: true });
}
scrollListener(e) {
const scrollingDown = this.previousScrollYPos < window.scrollY;
if (scrollingDown && this.previousScrollYPos === 0) {
this.stickyElement.classList.add(this.stickyClass);
} else if (!scrollingDown && window.scrollY === 0) {
this.stickyElement.classList.remove(this.stickyClass);
}
this.previousScrollYPos = window.scrollY;
}
}
A header that sticks to the top of the viewport as users scroll.
How position sticky works
There are 3 parts to getting position: sticky
to work.
- Sticky item - the element with
position: sticky
applied. - Sticky container - the parent of the sticky item. When an element has
position: sticky
applied, it’s immediate parent is automatically defined as the sticky parent. - Sibling content - the sticky item must have adjacent content to float above.
Scroll Padding
If you need to link to sections within a page using a sticky header, use scroll-padding-top
or scroll-margin-top
to ensure the content clears the sticky header. You can view a demo here. Note that the scroll padding is applied to the <html>
element, it will not work otherwise.
Scroll Listener
This component uses a scroll listener to check whether the header is stuck vs unstuck. To avoid scroll jank, the option passive: true
has been added. Learn more about passive listeners here.