Ever noticed a sticky header that changes style as you scroll—like the event dates on Luma's site?
They elegantly transition to a different visual treatment once they become sticky. It’s a small interaction, but it makes the UI feel polished and intentional.
I wanted to figure out how they were doing it.
CSS handles the stickiness (with position: sticky
), but there’s no built-in way to detect when it happens.
No CSS selector*. No JavaScript event.
I love figuring out how to replicate cool interactions I see on the web—so here’s how to do this one using the magical IntersectionObserver
API.
It’s widely supported, lightweight, and once you know the trick, you’ll start seeing opportunities to use it everywhere.
🧠 Read the full guide with live interactive demos on jakeisonline.com
Have you tried this approach, or come across similar patterns in the wild?
💡 Good news: We’ll soon be able to use container queries to detect when an element becomes sticky.
But as of this article’s publishing, it’s only available in Chrome, so you’re stuck with this for now
Top comments (2)
Really like how you used IntersectionObserver for sticky detection - makes those small transitions feel alive. Have you automated any style changes or effects once the element is sticky?
I have! As much as possible, I like to decouple state-based styling from JavaScript, so the callback in
IntersectionObserver
is simply changing a data attribute on the sticky element to denote the sticky state.That way I can rely on CSS to handle the styling changes, in the live example I'm using Tailwind CSS to achieve that:
If you're not familiar with Tailwind, the
data-[currently-sticky=true]
condition placed before any utility class means it's only applied when that condition is true.Doing this in vanilla CSS would largely look the same, probably using
.detect-sticky[data-currently-sticky="true"]
as the selector.