skip to Main Content

I’m trying to detect whenever a visitor has scrolled past elements on a page.

I would like to detect scrolling past every .title element, and add an .active class to the corresponding anchor menu item. The .active class should stay on the anchor menu item until scrolling past the next title element.

Here is what I have – adding the .active class works, but removing it fails.

Anyone able to help?

JsFiddle here.

window.addEventListener("scroll", function () {
  document.querySelectorAll('.title').forEach((section) => {
    const id = section.getAttribute('id');
    if (id) {
      if (window.scrollY > (section.offsetTop + section.offsetHeight)) {
        document.querySelector(`.menu li a[href="#${id}"]`).classList.add('active');
      } else {
        document.querySelector(`.menu li a.active`).classList.remove('active');
      }
    }
  });
});
.active {
  color: red
}
<ul class="menu">
  <li><a href="#one">Link one</a></li>
  <li><a href="#two">Link two</a></li>
  <li><a href="#three">Link thre</a></li>
  <li><a href="#four">Link four</a></li>
  <li><a href="#five">Link five</a></li>
</ul>

<div class="container">
  <div class="title" id="one">Title one</div>
  <p>
    Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec cursus dolor id ullamcorper tempor. Donec ut ullamcorper tellus. Etiam vel rhoncus urna. Aenean augue nulla, congue a orci at, imperdiet vehicula eros. Aenean ornare nibh ut leo faucibus fringilla. Quisque varius ut ipsum egestas feugiat. Mauris id nisl ultrices, consectetur mauris in, consectetur mi. Sed sit amet dolor urna. Nullam nec enim gravida, pulvinar lacus ut, volutpat nibh. Quisque commodo eu tortor ac dictum. Vivamus sodales risus sed blandit vulputate. Proin elit erat, varius non tincidunt ut, semper sed erat. Nulla vehicula vitae nisl nec dignissim. Curabitur viverra risus eu est pellentesque lobortis. Nullam egestas semper convallis.

    Ut ac blandit risus, sit amet elementum ex. Donec rhoncus augue eu cursus consequat. Duis a sapien sit amet elit aliquet molestie. Mauris nec ligula viverra, ornare dolor vel, malesuada nisl. Proin gravida dolor justo, sit amet tempus justo consectetur ut. Aenean malesuada iaculis tortor ac varius. Phasellus ultrices purus nisi, eu rutrum felis bibendum id. Phasellus enim dui, ultrices sed massa vel, euismod bibendum eros. Duis quis auctor augue, eget pellentesque velit. In a est at neque dignissim pellentesque et tempus sem. Nulla et leo diam.
  </p>
  <div class="title" id="two">Title two</div>
  <p>
    Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec cursus dolor id ullamcorper tempor. Donec ut ullamcorper tellus. Etiam vel rhoncus urna. Aenean augue nulla, congue a orci at, imperdiet vehicula eros. Aenean ornare nibh ut leo faucibus fringilla. Quisque varius ut ipsum egestas feugiat. Mauris id nisl ultrices, consectetur mauris in, consectetur mi. Sed sit amet dolor urna. Nullam nec enim gravida, pulvinar lacus ut, volutpat nibh. Quisque commodo eu tortor ac dictum. Vivamus sodales risus sed blandit vulputate. Proin elit erat, varius non tincidunt ut, semper sed erat. Nulla vehicula vitae nisl nec dignissim. Curabitur viverra risus eu est pellentesque lobortis. Nullam egestas semper convallis.

    Ut ac blandit risus, sit amet elementum ex. Donec rhoncus augue eu cursus consequat. Duis a sapien sit amet elit aliquet molestie. Mauris nec ligula viverra, ornare dolor vel, malesuada nisl. Proin gravida dolor justo, sit amet tempus justo consectetur ut. Aenean malesuada iaculis tortor ac varius. Phasellus ultrices purus nisi, eu rutrum felis bibendum id. Phasellus enim dui, ultrices sed massa vel, euismod bibendum eros. Duis quis auctor augue, eget pellentesque velit. In a est at neque dignissim pellentesque et tempus sem. Nulla et leo diam.
  </p>
  <div class="title" id="three">Title three</div>
  <p>
    Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec cursus dolor id ullamcorper tempor. Donec ut ullamcorper tellus. Etiam vel rhoncus urna. Aenean augue nulla, congue a orci at, imperdiet vehicula eros. Aenean ornare nibh ut leo faucibus fringilla. Quisque varius ut ipsum egestas feugiat. Mauris id nisl ultrices, consectetur mauris in, consectetur mi. Sed sit amet dolor urna. Nullam nec enim gravida, pulvinar lacus ut, volutpat nibh. Quisque commodo eu tortor ac dictum. Vivamus sodales risus sed blandit vulputate. Proin elit erat, varius non tincidunt ut, semper sed erat. Nulla vehicula vitae nisl nec dignissim. Curabitur viverra risus eu est pellentesque lobortis. Nullam egestas semper convallis.

    Ut ac blandit risus, sit amet elementum ex. Donec rhoncus augue eu cursus consequat. Duis a sapien sit amet elit aliquet molestie. Mauris nec ligula viverra, ornare dolor vel, malesuada nisl. Proin gravida dolor justo, sit amet tempus justo consectetur ut. Aenean malesuada iaculis tortor ac varius. Phasellus ultrices purus nisi, eu rutrum felis bibendum id. Phasellus enim dui, ultrices sed massa vel, euismod bibendum eros. Duis quis auctor augue, eget pellentesque velit. In a est at neque dignissim pellentesque et tempus sem. Nulla et leo diam.
  </p>
  <div class="title" id="four">Title four</div>
  <p>
    Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec cursus dolor id ullamcorper tempor. Donec ut ullamcorper tellus. Etiam vel rhoncus urna. Aenean augue nulla, congue a orci at, imperdiet vehicula eros. Aenean ornare nibh ut leo faucibus fringilla. Quisque varius ut ipsum egestas feugiat. Mauris id nisl ultrices, consectetur mauris in, consectetur mi. Sed sit amet dolor urna. Nullam nec enim gravida, pulvinar lacus ut, volutpat nibh. Quisque commodo eu tortor ac dictum. Vivamus sodales risus sed blandit vulputate. Proin elit erat, varius non tincidunt ut, semper sed erat. Nulla vehicula vitae nisl nec dignissim. Curabitur viverra risus eu est pellentesque lobortis. Nullam egestas semper convallis.

    Ut ac blandit risus, sit amet elementum ex. Donec rhoncus augue eu cursus consequat. Duis a sapien sit amet elit aliquet molestie. Mauris nec ligula viverra, ornare dolor vel, malesuada nisl. Proin gravida dolor justo, sit amet tempus justo consectetur ut. Aenean malesuada iaculis tortor ac varius. Phasellus ultrices purus nisi, eu rutrum felis bibendum id. Phasellus enim dui, ultrices sed massa vel, euismod bibendum eros. Duis quis auctor augue, eget pellentesque velit. In a est at neque dignissim pellentesque et tempus sem. Nulla et leo diam.
  </p>
  <div class="title" id="five">Title five</div>
  <p>
    Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec cursus dolor id ullamcorper tempor. Donec ut ullamcorper tellus. Etiam vel rhoncus urna. Aenean augue nulla, congue a orci at, imperdiet vehicula eros. Aenean ornare nibh ut leo faucibus fringilla. Quisque varius ut ipsum egestas feugiat. Mauris id nisl ultrices, consectetur mauris in, consectetur mi. Sed sit amet dolor urna. Nullam nec enim gravida, pulvinar lacus ut, volutpat nibh. Quisque commodo eu tortor ac dictum. Vivamus sodales risus sed blandit vulputate. Proin elit erat, varius non tincidunt ut, semper sed erat. Nulla vehicula vitae nisl nec dignissim. Curabitur viverra risus eu est pellentesque lobortis. Nullam egestas semper convallis.

    Ut ac blandit risus, sit amet elementum ex. Donec rhoncus augue eu cursus consequat. Duis a sapien sit amet elit aliquet molestie. Mauris nec ligula viverra, ornare dolor vel, malesuada nisl. Proin gravida dolor justo, sit amet tempus justo consectetur ut. Aenean malesuada iaculis tortor ac varius. Phasellus ultrices purus nisi, eu rutrum felis bibendum id. Phasellus enim dui, ultrices sed massa vel, euismod bibendum eros. Duis quis auctor augue, eget pellentesque velit. In a est at neque dignissim pellentesque et tempus sem. Nulla et leo diam.
  </p>
</div>

2

Answers


  1. Try to add this script i think it should work we need one function to check if an element is in the viewport.

    window.addEventListener("scroll", function() {
      let activeMenuItem = null;
      
      // Iterate through each .title element
      document.querySelectorAll('.title').forEach((section) => {
        const id = section.getAttribute('id');
        
        if (id) {
          // Check if the user has scrolled past this .title element
          if (window.scrollY > (section.offsetTop + section.offsetHeight)) {
            // If scrolled past, mark the current .title's corresponding menu item as active
            activeMenuItem = document.querySelector(`.menu li a[href="#${id}"]`);
          }
        }
      });
    
      // Remove active class from all menu items
      document.querySelectorAll('.menu li a').forEach((menuItem) => {
        menuItem.classList.remove('active');
      });
    
      // Add active class only to the last identified menu item
      if (activeMenuItem) {
        activeMenuItem.classList.add('active');
      }
    });
    Login or Signup to reply.
  2. The provided code is almost correct, but it fails to remove the .active class from the previous menu item when scrolling past a new title element. The issue lies in the else block of the scroll event listener, where the code attempts to remove the .active class from all elements with the class .menu li a.active.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search