Help with scrolling submenu, IntersectionObserver
I'm rewriting some old code we had that used window.onScroll to set the active state of the current sub-section of the page. I'm trying to use IntersectionObserver, but with short sections, it's observing two active sections at once. Essentially I'm looking to mimic the behavior of the side nav on Mozilla: https://developer.mozilla.org/en-US/docs/Web/API/Element/scroll_event - it only marks a section as active when it's on the top close to the sticky menu. Anybody have any good resources or code with examples?? Thanks!
Element: scroll event - Web APIs | MDN
The scroll event fires when an element has been scrolled.
To detect when scrolling has completed, see the Element: scrollend event.
14 Replies
Are you sure that this is practical to do with intersection observer? The root is required to be an ancestor of the element being observed, and the maximum threshold is 1. It can be used to detect when the element has been scrolled into view, but I don't see a practical way for it to detect when the element reaches the top of the view or the top of its ancestor. Using the scroll event as you did before seems much more practical.
I agree, I was suspecting it needed to be the scroll event, it just seems like everywhere I looked people were recommending IO instead. I tried looking at the source of the MDN page to see how theirs was implemented, but no luck lol.
I have noticed that intersection observer recently became very popular. The Map collection has too. I don't know where this is coming from, since both have existed for many years. I suspect some popular Youtuber just recently discovered them.
If you are referring to the MDN page for intersection observer, they have an array of thresholds and it's tracking different intersection ratios, but all the ratios are between 0 and 1. It can't track past 1, which is what you would need for this to work.
I meant, the MDN page has a sidebar sub-nav which is doing exactly what I want - changing the 'active' item to be active only when the heading gets to the top of the sticky header. But I suspect, since the height of the header can theoretically changed based on window size and resize, that it needs to be a scroll observer.
I forgot which post I was commenting on. I don't see any way to do that with an intersection observer. It still wouldn't be practical even if the height of the header is a known fixed value. The header is not an ancestor of any of the links. Most people who recommend intersection observer have a vague idea of what it does, but they haven't mastered the specifics. There is an official rule that the root must be either the viewport or an ancestor of the observed element. It can't be just any random element on the page.
Right, I was trying to do it based on the (calculated) height of the sticky header and do that as a negative root viewport, but it wasn't working.
I am definitely going to go back to a passive scroll event. π Thank you!!!
I just realized that this effect can be done in pure CSS. All you need is a linear gradient that goes from transparent up to the background color. With the proper z-index for everything, this should work.
Really?? How so?
If you put the gradient at the top of the side bar and it has a higher z-index than the links, the links will go beneath it. Since part of the gradient is transparent, the link will show and it will smoothly transition to being occluded as you scroll further up along the gradient to the opaque part.
Ohhh! Actually my issue is specifically a sticky nav at the top of the page (below a sticky header) so that wouldn't work for me. But it was the example that the MDN nav only changed when the section reached the bottom of the sticky header that I wanted to mimic.
I though you were trying to get the links to fade upon reaching the top.
The nav at the top doesn't need an intersection observer and it also doesn't need any scroll events. Now I'm confused about what you are trying to do.
I just reread the post and I think I totally misunderstood. If you want to detect which section appears in the viewport, you can use intersection observer and use that to set which part of the nav is marked as active.
Oh. Okay. So, here's my setup.
-header (gets sticky based on scroll)
--layout-container (thanks, drupal)
---nav (gets sticky based on scroll)
---section 1
---section 2
---etc
But I only want the nav bar 'active' item to be active when an item reaches the top of the sticky nav. With short items, multiple items are fully in viewport at the same time.
MDN's site was the only one I'd seen where they aren't either "active when the next item reaches viewport" or "make section full page height"
Reaching the top is still a problem. Why not just when the section is more than a certain amount in view?
I feel like I'd have multiple active items