Search code examples
javascriptscrollparent-childevent-listenerintersection-observer

Scroll child element when in viewport


Can someone help?

I have multiple sticky child elements, some of these has an high height (more than the viewport). Each child has the following structure:

<section>
  <div class="content">
    <div class="child"></div>
    ... 20 more child ...
  </div>
</section>

with the following css:

section {
  min-height: 682px;
  position: sticky;
  top: 80px;
}
.content {
  height: 618px;
  overflow-y: scroll;
  display: flex;
  flex-direction: column;
  gap: 5px;
}
.child {
  height: 120px;
}

How can i achieve this scroll behaviour:

  1. first i scroll normally the body
  2. when i reach the section with high height i need to scroll the section until i touch the bottom
  3. when i reach the bottom of the section i need to scroll normally the body

I need to achieve this without manually scroll the section content but only scrolling the body scrollbar..

I already write the IntersectionObserver that observe the section with high height.

I think a simple solution is to change the "focus" of the scroll between parent and child when necessary but I don't know what the best way to solve this is in js.

I already try to add a scroll event listener and then scroll the content of the section with section.scrollBy(0, event.deltaY);

But the event.deltaY doesnt exist in the type event: Event in ts...


Solution

  • Try to use a combination of Intersection Observer and event listeners.

    You can set Intersection Observer to observe the section with high height and when it becomes fully visible in the viewport,trigger a function.

    const section = document.querySelector('section');
    
    const observer = new IntersectionObserver((entries) => {
      entries.forEach((entry) => {
        if (entry.isIntersecting) {
          // Call a function to handle scrolling behavior
          handleSectionScroll();
        }
      });
    });
    
    observer.observe(section);
    
    

    In the handleSectionScroll function, you can add a scroll event listener to the body to control the scrolling behavior.

    const handleSectionScroll = () => {
      document.body.addEventListener('wheel', scrollBody);
    
      const scrollBody = (event) => {
        const sectionHeight = section.getBoundingClientRect().height;
        const bodyHeight = document.body.getBoundingClientRect().height;
        const scrollPosition = window.pageYOffset;
    
        if (scrollPosition < section.offsetTop) {
          // Scroll normally
          return;
        }
    
        if (scrollPosition >= section.offsetTop && scrollPosition < 
           section.offsetTop + sectionHeight - bodyHeight) {
           // Scroll the section
           section.scrollBy(0, event.deltaY);
           event.preventDefault();
        } else {
          // Scroll normally
          return;
        }
      }
    }
    

    Try this code and let me know the result.