I followed @mattrick example of using a IntersectionObserver
giving a bound on the rootMargin
and attached it to the physical header
. I am just answering for the sake of adding additional information to @mattrick's answer since @mattrick didn't provide an example.
IntersectionObserver emits a IntersectionObserverEntry when triggered, which has a isIntersecting
property that indicates whether or not the actual header is intersecting the viewport
or the element
.
In this case:
Note that my implemenation is using Tailwind
and Typescript
but can be created in base CSS
and JS
.
<!doctype html>
<html>
<head></head>
<body class="flex flex-col min-h-screen">
<header id="header" class="banner flex flex-row mb-4 p-4 sticky top-0 z-50 w-full bg-white"></header>
<main id="main" class="main flex-grow"></main>
<footer class="content-info p-4 bg-linear-footer bottom-0 mt-4"></footer>
</body>
</html>
Note: The <header>
requires a id
of header for the js to reference the element.
export class Header {
static checkSticky() {
const header = document.getElementById("header");
if (header == null) {
return; // Abort
}
const observer = new IntersectionObserver(
([entry]) => this._handleStickyChange(entry , header) ,
{
rootMargin: '-1px 0px 0px 0px',
threshold: [1],
}
);
observer.observe(header);
}
static _handleStickyChange(entry : IntersectionObserverEntry , header : HTMLElement ) {
if (!entry.isIntersecting) {
header.classList.add("your-class");
return; // Abort further execution
}
header.classList.remove("your-class");
}
}
Call Header.checkSticky()
when the DOM is ready to start observing the header. The observer will trigger _handleStickyChange()
reactively based on whether the header is intersecting the viewport.
This allows you to add visual effects (e.g., shadows, background changes) or trigger callbacks when the header becomes sticky.
Thanks @mattrick for your initial contribution.