Sticky Page Header Shadow on Scroll
Posted on Apr 2, 2023
Takes about 2 minutes to read
We've seen it plenty of times around the web where a website's page header follows us as we scroll down the page. CSS makes doing this a breeze with sticky positioning:
.page-header {
position: sticky;
top: 0;
}
What if we desired something a little bit extra, like applying a box-shadow
to the sticky header as soon as the page is scrolled? I thought it was worth sharing one solution that has worked well for me to accomplish this goal. Check out the following CodePen demo. As soon as the page is scrolled, a shadow fades in below the header.
See the pen (@hexagoncircle) on CodePen.
An element that I've decidedly dubbed an "intercept"—naming is hard and this felt right in the moment—is created and inserted above the page header at the top of the page. If we open the browser dev tools and inspect the DOM, we'll find:
<div data-observer-intercept></div>
<header id="page-header">
//...
</header>
The Intersection Observer API is being used to observe when the intercept is no longer appearing in the visible viewport area which happens as soon as the page scrolls. So when the intercept is not intersecting, a class is applied to the header element.
const observer = new IntersectionObserver(([entry]) => {
header.classList.toggle("active", !entry.isIntersecting);
});
observer.observe(intercept);
Inspecting the DOM again, we'll catch the active
class name on the page header element toggling on and off as we scroll down and back up.
Delay that shadow
It's also possible to wait on when the shadow should appear by offsetting the intercept element. Try editing the above demo on CodePen. In the CSS panel add the following ruleset:
[data-observer-intercept] {
position: absolute;
top: 300px;
}
This will push the intercept down from the top of the page by 300 pixels. When scrolling the page again, notice that the shadow doesn't appear right away, waiting until the page has been scrolled passed the offset value.
Have questions? Other ways to handle this? I'd love to hear about it! Reach out to me on Mastodon with your ideas.
Webmentions for this post
20 mentions
-
🔗 Good link: ryanmulligan.dev/blog/sticky-he…
-
thank you. nice. always trying to solve this.
-
I'd have to see a demo to understand. Can you resolve this issue shown below using your mentioned resolution?
-
Also should apologise: I thought that was your article @piccalilli_ .
-
Doesn't work when content inside has a background, this was the very first link I tried 😏
-
If it's a light background, you can use the multiply blend mode
-
Good share 🫶
-
I feel like yours and @ste_bau 's last post will compliment each other very nicely.
-
Ah yeh, we've been able to do that with CSS for over a decade now! lea.verou.me/2012/04/backgr…
-
> I'd rather implement a solution that works for all cases Wouldn't we all, but you certainly won't get that with JavaScript. Anyway, cool article and a nice trick!
-
Ok I'll check it out. Though, I'd rather implement a solution that works for all cases, rather than specific ones.
-
well know because that's a red background. Best bet is to look up mix-blend-mode. I wrote a lesson on it in Learn CSS web.dev/learn/css/blen…
-
👁🗨Sticky Page Header Shadow on Scroll by Ryan Mulligan @hexagoncircle @hexagoncircle@fosstodon.org #StickyHeader #css #js #webdev ryanmulligan.dev/blog/sticky-he…
-
Thanks man! 😄
-
just implemented this! nice one 🧑💻
-
This is smooth: ryanmulligan.dev/blog/sticky-he…. Well done @hexagoncircle
-
Nice, that’s a clean approach 👏🏻
-
What we really need here is a :sticky pseudo-class. That would be a total game changer.
-
Is there a way to make a fancy sticky header that’s accessible? For instance, one where elements in focus never fall “behind” the header?
-
not sure tbh