Search code examples
javascriptjquerycssscroll-snap

CSS Scroll Snap get active Item


I have a problem with CSS scroll snap. I want to detect the snapped element via JavaScript and assign it, e.g., a CSS class or similar.

Unfortunately, I haven't found a way to detect the snapped element yet. Background: I have a list with subitems, which are scrolled, always the middle item in the list should be highlighted:

Layout

Layout

I already tested the intersection observer with rootMargin to detect the vertically centered element, but it’s more buggy than useful.

HTML

<div class="timeline-menu-dropdown-years-list-container">
    <ul class="timeline-menu-dropdown-years-list timeline-menu-dropdown-years-text" id="yearcontainer">
        <li id="2010" class="timeline-dropdown-year" data-target="year-2010">2010</li>
        <li id="2009" class="timeline-dropdown-year" data-target="year-2009">2009</li>
        <li id="2008" class="timeline-dropdown-year" data-target="year-2008">2008</li>
        <li id="2007" class="timeline-dropdown-year" data-target="year-2007">2007</li>
        <li id="2006" class="timeline-dropdown-year" data-target="year-2006">2006</li>
        <li id="2005" class="timeline-dropdown-year" data-target="year-2005">2005</li>
        <li id="2004" class="timeline-dropdown-year" data-target="year-2004">2004</li>
        <li id="2003" class="timeline-dropdown-year" data-target="year-2003">2003</li>
        <li id="2002" class="timeline-dropdown-year" data-target="year-2002">2002</li>
        <li id="2001" class="timeline-dropdown-year" data-target="year-2001">2001</li>
        <li id="2000" class="timeline-dropdown-year" data-target="year-2000">2000</li>
    </ul>
</div>

CSS

.timeline-menu-dropdown-years-list-container {
  max-height: 250px;
  overflow: scroll;
  scroll-snap-type: y mandatory;
  -ms-overflow-style: none;  /* Internet Explorer and Edge */
  scrollbar-width: none;  /* Firefox */
  padding-top: 45%;
  padding-bottom: 40%;
  scroll-padding-top: 45%;
  scroll-padding-bottom: 40%;
}

.timeline-dropdown-year {
  color: white;
  font-size: 14px;
  border-bottom: 2px solid white;
  margin-right: 11%;
  margin-left: 34%;
  scroll-snap-align: center;
}

How can I fix it?

At the end, you should be able to scroll through this timeline. The active element should always snap to the center and be visually highlighted.


Solution

  • I have the same problem. I solved it with JavaScript here: Implementation of CSS scroll snap event stop and element position detection

    [].slice.call(container.children).forEach(function (ele, index) {
        if (Math.abs(ele.getBoundingClientRect().left - container.getBoundingClientRect().left) < 10) {
            // The 'ele' element at this moment is the element currently
            // positioned. Add class .active for example!
    
        } else {
            // The 'ele' element at the moment is not
            // the currently positioned element
        }
    });
    

    Put this in the event scroll:

    // Timer, used to detect whether horizontal scrolling is over
    var timer = null;
    // Scrolling event start
    container.addEventListener('scroll', function () {
        clearTimeout(timer);
        // Renew timer
        timer = setTimeout(function () {
            // No scrolling event triggered. It is considered that
            // scrolling has stopped do what you want to do, such
            // as callback processing
        }, 100);
    });