jquerycssanchorscrolltop

Clicking anchor links rendering incorrect scrollTop value (all browsers)


I am building a page which features a header which is hidden out of view (negative TOP value) when scrolling down and returns to view when scrolling up. No problems there, working fine. I also have a menu on the page which features anchor links to smooth-scroll to different sections of the page.

The problem I am experiencing is that when clicking an anchor link, the [hidden] header jumps down back into view very quickly and instantly goes back to its hidden position. (It should be hidden, since clicking an anchor link is causing us to scroll DOWN the page.)

Edit: It also does this when clicking an anchor link results in scrolling UP; i.e. the header should be in view, but when the anchor link is clicked it does a momentary jump out of view and then pops back down.

To debug, I have logged to console the "before/after" values of $(window).scrollTop(), notated as "curScrollTop" and "lastScrollTop". These are the values we are using to compare to one another to determine if we are scrolling UP or DOWN. What is interesting, and frustrating, is that when clicking an anchor link, the "curScrollTop" value suddenly becomes a ridiculous, incorrect value - and I believe this is what is causing the header to jump back into view for a split-second.

Has anyone had this issue? Better yet, why is this happening and how to work-around or fix this?

$(document).ready(function(){

        //do smooth scrolling when anchor links are clicked
    $('a[href^=#]').click(function(){
        let divid=this.hash;
        $('html,body').animate({scrollTop: $(divid).offset().top-80}, 1000);
                //subtract 80 from $(divid).offset().top to put div where we want it

                monitorScrolling();

    });

});


function monitorScrolling()
{
    $(window).scroll(function(){
        let curScrollTop = $(window).scrollTop();
        console.log('cur '+curScrollTop+' last '+lastScrollTop);
        if (curScrollTop > lastScrollTop)
        {
        //scrolling down
        $('#header-container').attr('class','header-container-off');
        $('#desktop-menu').attr('class','desktop-menu-top');
        lastScrollTop=curScrollTop-10; //subtract 10 to handle "bounce" on mobile devices
        }
        else
        {
        //scrolling up
        $('#header-container').attr('class','header-container-on');
        $('#desktop-menu').attr('class','desktop-menu');
        lastScrollTop=curScrollTop+10; //add 10 to handle "bounce" on mobile devices
        }
      });

}

Here are the values recorded in the console:

//Here we have scrolled down a bit so that our header is now hidden
cur 1 last 0
cur 13 last -9
cur 24 last 3
cur 37 last 14
cur 66 last 27
cur 78 last 56
cur 88 last 68
cur 95 last 78
cur 99 last 85
cur 100 last 89
//Anchor link was clicked, smooth-scrolling down to appropriate div - incorrect values!!!!
cur 1259 last 90
cur 102 last 1249
cur 104 last 112
cur 112 last 114
cur 117 last 122
cur 125 last 127
cur 139 last 135

I have played with the numbers a bit (resetting scrollTop, etc.) but always same result.


Solution

  • You haven't told the browser not to do what it would normally do by using preventDefault();

    $('a[href^="#"]').click(function(e){ // <--- e is defined here by the way
      e.preventDefault();
      let divid=this.hash;
      $('html,body').animate({scrollTop: $(divid).offset().top-80}, 1000);
      //subtract 80 from $(divid).offset().top to put div where we want it
    });
    

    https://jsfiddle.net/d2zexbn7/