Traversing back to parent and go to all its child element with ($this)

Viewed 272

I wanted to add classes on my anchor links based on how far the user has scrolled, using Jquery. I was able to add class but it wont be removed using removeClass. I'm sure the problem is the selectors im using in jquery. Do i need to traverse back and add specific selectors from parent element instead of assigning directly the removeClass on my anchor links.

Instead of adding classes to the list elements, I'd rather apply the classes to the anchor links itself which is my personal choice.

HTML

<ul>
    <li><a class="scroll" href="#first">About Me</a></li>
    <li><a class="scroll" href="#second">Portfolio</a></li>
    <li><a class="scroll" href="#third">Contact</a></li>
</ul>

<div class="home" style="height:1000px; background-color:red;"></div>
<div class="about-me" id="first" style="height:1000px; background-color:green;"></div>
<div class="portfolio" id="second" style="height:1000px; background-color:blue;"></div>
<div class="contact" id="third" style="height:1000px; background-color:orange;"></div>

CSS

 .active {
  color:gray;
  }

JQUERY

$(document).ready(function(){
var scrollLink = $('.scroll');

scrollLink.click(function(event){
    event.preventDefault();
    $('body,html').animate({
        scrollTop: $(this.hash).offset().top
    }, 1000)
})

$(window).scroll(function(){
    var scrollLoc = $(this).scrollTop();

    scrollLink.each(function(){

        var traverse = $(this.hash).offset().top - 20;

        if (traverse <= scrollLoc){
            $(this).addClass('active');
            $(this).removeClass('active');
        }
    })
})

})  

I expect that classes from other anchor links would be removed when they are not shown on screen.

2 Answers

I think you might want to change the following code

if (traverse <= scrollLoc){
   $(this).addClass('active');
    $(this).removeClass('active');
}

into something like this:

if (traverse <= scrollLoc){
   $(this).addClass('active');
} else { 
    $(this).removeClass('active');
}

You need to adjust your condition to have a lower and upper bound. Since your elements has the same height it should be easy.

$(document).ready(function() {
  var scrollLink = $('.scroll');

  scrollLink.click(function(event) {
    event.preventDefault();
    $('body,html').animate({
      scrollTop: $(this.hash).offset().top
    }, 1000)
  })

  $(window).scroll(function() {
    var scrollLoc = $(this).scrollTop();

    scrollLink.each(function() {

      var traverse = $(this.hash).offset().top - 20;

      if (traverse <= scrollLoc && traverse + 1000 >= scrollLoc ) {
        $(this).addClass('active');
      } else {
        $(this).removeClass('active');
      }
    })
  })

});
.active {
  color: gray;
}

ul {
  position: fixed;
  background:#fff;
  padding:5px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<ul>
  <li><a class="scroll" href="#first">About Me</a></li>
  <li><a class="scroll" href="#second">Portfolio</a></li>
  <li><a class="scroll" href="#third">Contact</a></li>
</ul>

<div class="home" style="height:1000px; background-color:red;"></div>
<div class="about-me" id="first" style="height:1000px; background-color:green;"></div>
<div class="portfolio" id="second" style="height:1000px; background-color:blue;"></div>
<div class="contact" id="third" style="height:1000px; background-color:orange;"></div>

In case height is not the same you can do this:

$(document).ready(function() {
  var scrollLink = $('.scroll');

  scrollLink.click(function(event) {
    event.preventDefault();
    $('body,html').animate({
      scrollTop: $(this.hash).offset().top
    }, 1000)
  })

  $(window).scroll(function() {
    var scrollLoc = $(this).scrollTop();

    scrollLink.each(function() {

      var traverse = $(this.hash).offset().top - 20;
      var traverse_up = $(this.hash).offset().top - 20 + $(this.hash).height();

      if (traverse <= scrollLoc && traverse_up >= scrollLoc ) {
        $(this).addClass('active');
      } else {
        $(this).removeClass('active');
      }
    })
  })

});
.active {
  color: gray;
}

ul {
  position: fixed;
  background:#fff;
  padding:5px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<ul>
  <li><a class="scroll" href="#first">About Me</a></li>
  <li><a class="scroll" href="#second">Portfolio</a></li>
  <li><a class="scroll" href="#third">Contact</a></li>
</ul>

<div class="home" style="height:200px; background-color:red;"></div>
<div class="about-me" id="first" style="height:1000px; background-color:green;"></div>
<div class="portfolio" id="second" style="height:800px; background-color:blue;"></div>
<div class="contact" id="third" style="height:900px; background-color:orange;"></div>

Related