5

I'm trying to implement a small code with which I can get smooth scrolling when I click on anchor (and anchor name appears after animation) and I would like to return to the top of page if I push on the back button of the browser and update the URL (without #anchor name).

Here's the code :

$(function() {
  // Smooth scrolling when clicking on anchor
  $('a[href*=#]:not([href=#])').click(function(event) {
    event.preventDefault();
    if (location.pathname.replace(/^\//,'') == this.pathname.replace(/^\//,'') && location.hostname == this.hostname) {
      var target = $(this.hash);
      target = target.length ? target : $('[name=' + this.hash.slice(1) +']');
      if (target.length) {
        var hash = this.hash; 
        $('html,body').animate({ scrollTop: target.offset().top - 55}, 300, function() {
          location.hash = hash;
          href = window.location.href;
          history.pushState({page:href}, null, href);
        });
        return false;
      }
    }
  });
  // Get smooth scrolling to the top whith back button of browser
  $(window).bind('popstate', function(event) {
    var state = event.originalEvent.state;
    var target = window.location.href.split('#');
    var href = target[0];
    if (state) {
      $('html,body').animate({ scrollTop: 0 }, 300, function() {
        window.location.href = href;
     })
   }
  });

  // First page loading
  window.onload = function() {
    history.replaceState({ path: window.location.href }, '');
  }
});

All the above functionalities work well under Safari and Chrome. But this is not the case with Firefox: once smooth scrolling down is performed, I need to click twice on back button to be redirected on the top of page.

I have seen this other question on stackoverflow and tried to do with and without event.preventDefault, also by putting only :

$('html').animate

or $('body').animate

but the behavior is the same.

If someone could see why it doesn't work.

Thanks

Community
  • 1
  • 1

1 Answers1

1

You are triggering additional history change in this line location.hash = hash;

So, I did a couple of changes to your code, and it works in my FF now.

In click handler,

   $('html').animate({ scrollTop: target.offset().top - 55}, 300, function() {
      href = window.location.href;
      history.pushState({page:href}, null, href.split('#')[0]+hash);
    });

Also, it seems like $('html,body').animate runs callback twice, therefore messing with history. That's why I left only html.

In popstate handler I removed page reload, but you can keep it, if you wish:

if (state) {
  $('html,body').animate({ scrollTop: 0 }, 300)
Serge Seredenko
  • 3,541
  • 7
  • 21
  • 38
  • thanks for your answer, it seems to work well but I would like to avoid reloading the page when I return to the top of page : is it possible to modify the URL (actually remove the #anchor) without using "window.location.href = href" ? –  Feb 07 '16 at 20:45
  • Another remark : If I don't use callback into $('html,body').animate({ scrollTop: 0 }, 300), the animation is not achieved (smooth scrolling), I go directly to anchor without smooth scrolling. –  Feb 07 '16 at 20:52
  • Finally, I used "history.pushState({}, null, newUrl)" to return to top without reloading page, thanks –  Feb 07 '16 at 22:05
  • @user1773603 Last 3 lines of my answer are about page reload. Didn't removal of `window.location.href = href;` work? – Serge Seredenko Feb 07 '16 at 22:54
  • I replaced by "history.replaceState({}, null, href)" and with this, it doesn't reload page, thanks –  Feb 08 '16 at 11:57