1

I have a jQuery code obtained from w3schools.com which ON CLICK (clicking an <a href="#id"></a>) changes URL's #id and also allows smooth scrolling to a particular DIV section. But its not working on scroll. I want the same with an scrolling effect. When I scroll down or up to a particular section the URL's #id should change.

Current jQuery Code:

$(document).ready(function(){
  $("#navlist a").on('click', function(event) {
    if(this.hash !== ""){
      var hash = this.hash;
        $('html, body').animate({
        scrollTop: $(hash).offset().top
      }, 800, function(){
        window.location.hash = hash;                
      });
    }
  });
});

I searched on stackoverflow and I got something like this:

$(document).bind('scroll',function(e){
    $('div').each(function(){
        if ($(this).offset().top < window.pageYOffset + 10 && $(this).offset().top + $(this).height() > window.pageYOffset + 10){
            window.location.hash = $(this).attr('id');
        }
    });
});

This seems to work but when I place both the code either one of them is stopping the other one from executing. I thought of combining both the codes into one to achieve both onclick and scroll effect but I am not being able to do so (weak hands on jquery yet).

Example URL with ID: http://localhost/sites/fh/index.php#first

Please help me devs.

1 Answers1

1

Instead of setting the location hash, you should change the history state. That way you will avoid forced page scrolling by browser. Check it below:

navlist = [];
$("#navlist a").each(function(i) {
    var thisLink = $(this);
    var thisId = thisLink.attr('href');
    var thisTarget = $(thisId);
    navlist.push({
        'anchor': thisLink,
        'id': thisId,
        'target': thisTarget
    });
    thisLink.on('click', function(e) {
        e.preventDefault();
        $('html, body').animate({
            scrollTop: thisTarget.offset().top
        }, 800);
    });
});
$(window).on('scroll resize', function(e) {
    $.each(navlist, function(e, elem) {
        var placement = elem.target[0].getBoundingClientRect();
        if( placement.top<window.innerHeight && placement.bottom>0 ) {
            history.pushState({}, '', elem.id);
            console.log('Hash: ' + elem.id);
            return false; /* Exit $.each loop */
        };
    });
});
nav a {
    display: block;
}
section {
    height: 600px;
    border-top: 1px solid black;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<nav id="navlist">
    <a href="#s1">Go to Section 1</a>
    <a href="#s2">Go to Section 2</a>
    <a href="#s3">Go to Section 3</a>
</nav>
<section id="s1">Section 1 Content</section>
<section id="s2">Section 2 Content</section>
<section id="s3">Section 3 Content</section>

Also on JSFiddle.

Please note, if you are using Foundation framework, than you already have Magellan. For Bootstrap it is called ScrollSpy.

skobaljic
  • 8,855
  • 1
  • 23
  • 47
  • perfect.. and if I want to change navigation's font color to white on each scroll ? That would be a great help.. –  Feb 08 '17 at 10:08
  • In console, I never read `Hash: #s3` but only `Hash: #s1` and `Hash: #s2`, so apparently you never push state for section 3 – Yuri Feb 08 '17 at 11:05
  • You would have to resize browser and scroll down in a way the Section 3 start is above the viewport. – skobaljic Feb 08 '17 at 13:03