114

If you go to a page a and scroll around then refresh the page will refresh at the spot where you left it. This is great, however this also occurs on pages where there is a anchor location in the url. An example would be if you clicked on a link http://example.com/post/244#comment5 and refreshed the page after looking around you would not be at the anchor and the page jumps around. Is there any way to prevent this with javascript? So that no-matter-what you would always navigate to the anchor.

ThomasReggi
  • 55,053
  • 85
  • 237
  • 424

9 Answers9

162

On Chrome, even if you force scrollTop to 0 it will jump afterwards after the first scroll event.

You should bind the scroll to this:

$(window).on('beforeunload', function() {
    $(window).scrollTop(0);
});

So the browser is tricked to believe that it was on the beginning before the refresh.

josetapadas
  • 2,589
  • 3
  • 19
  • 19
  • 5
    Way more useful than the accepted answer if you don't want to mess around with scrolling. – Dan Abramov Oct 28 '13 at 20:09
  • 2
    This is not doing the job in Chrome 33. I mean it does scroll to the top before loading the new page. However the browser still remembers the previous scroll position somehow and performs the same autoscroll to that position. – Haralan Dobrev Dec 18 '13 at 10:07
  • 1
    Tested on Chrome 36, Firefox 30 and IE 11. Works very well! – Fizzix Aug 07 '14 at 01:46
  • 32
    For non-jQuery implementation: `window.onbeforeunload = function(){ window.scrollTo(0,0); }` – ProfNandaa Nov 10 '14 at 06:09
  • Is there a way to do something like this to prevent the browser from zooming to the previous zoom level? – Frank Feb 09 '15 at 19:22
  • 6
    Why did you choose 'beforeunload' event instead of 'unload'. My tests shows that last one allow to avoid jump to top before page would be are really unloaded by browser. – Aleksandr Zonov Jun 13 '15 at 22:09
  • 1
    It works for me but i don't know why i need to click refresh button twice now after adding this code in onbeforeunload. When clicked for the first time it just goes to top of the page and nothing else. I use angular btw. – Vinay Aug 23 '16 at 09:59
  • 1
    In Chrome 59 it makes Chrome auto-scroll to the top after the page is refreshed. If I don't want Chrome to auto-scroll anywhere and go to a specific position on the page by using JS, this still doesn't solve the issue, as any position I scroll to through JS will get overridden by Chrome's auto-scroll and it will scroll to the top of the page afterwards. – Tom Pažourek Aug 02 '17 at 18:14
  • 1
    @TomPažourek seems have to set a timeout – aboutqx May 21 '18 at 04:25
  • @DanAbramov I see what you did there – catamphetamine Apr 24 '19 at 22:29
125

To disable automatic scroll restoration just add this tag to head section.

<script>history.scrollRestoration = "manual"</script>

Supported by all modern browsers

Yarin
  • 173,523
  • 149
  • 402
  • 512
iimos
  • 4,767
  • 2
  • 33
  • 35
  • 3
    This would be the best answer if it was available in IE / Edge. You can vote for it to be implemented here though: https://wpdev.uservoice.com/forums/257854-microsoft-edge-developer/suggestions/17257562-implement-history-scrollrestoration – pjk_ok Aug 20 '18 at 01:50
  • 10
    This should be really a correct answer in 2019. None of other methods are 100% working. – Limbo Jan 17 '19 at 15:34
  • 5
    Can confirm this is the best solution. Other solutions here don't work on Mobile Safari and can be janky. This works perfectly. – user3330820 Jun 21 '19 at 13:15
  • Indeed It is the best answer. When you are refreshing a page the beforeunload functionality will jump to the top before the page is refreshed so it won't look good, ANd who cares about IE anyways – Xequtor Jun 10 '22 at 06:45
  • This is the answer. As of 2020 it works on Edge, and therefore all modern browsers. https://caniuse.com/mdn-api_history_scrollrestoration – Yarin Oct 13 '22 at 14:56
  • Everyone is recommending other things - various forms of scrollTo(0,0). None of it worked for me. This worked perfectly right off the bat. Thank you!! – purplefloyd Feb 27 '23 at 05:44
26

After number of failures finally I managed to do the trick. anzo is correct here as using beforeunload will make the page jump to top when a user reloads the page or clicks a link. So unload is the clearly way to do this.

$(window).on('unload', function() {
   $(window).scrollTop(0);
});

Javascript way(Thanks ProfNandaa):

window.onunload = function(){ window.scrollTo(0,0); }

EDIT: 16/07/2015

The jump issue is still there with Firefox even with unload event.

Community
  • 1
  • 1
Janaka Dombawela
  • 1,337
  • 4
  • 26
  • 49
  • 3
    This solution is much better than the `beforeunload` solution because it prevents jumping to the top of the page on reloads and anchor clicks. – BradGreens Mar 10 '16 at 20:31
  • 1
    @BradGreens With modern Chrome, onunload event is also triggered when user switch to other tabs, which is unexpected. onbeforeunload is still valid workaround. – Telvin Nguyen Feb 11 '19 at 11:33
  • @TelvinNguyen Can you give any resource on this? I tested this on google chrome 72 and still working fine for me. – Janaka Dombawela Feb 12 '19 at 05:07
  • @JanakaDombawela What I stated: Shifting new tab which would cause problem is incorrect. However, you can see the event onunload in this example does not triggered properly, even with jQuery 1.9.1 vs jQuery 1.8.3. onunload is unreliable. https://jsfiddle.net/6s4jhdug/3/ (1.8.3) https://jsfiddle.net/frt45ue9/ (1.9.1) – Telvin Nguyen Feb 13 '19 at 08:51
16

This solution is no longer recommended due to changes in browser behavior. See other answers.

Basically, if an anchor is used we bind to the windows scroll event. The idea being that the first scroll event has to belong to the automatic repositioning done by the browser. When this occurs we do our own repositioning and then remove the bound event. This prevents subsequent page scrolls from borking the system.

$(document).ready(function() {
    if (window.location.hash) { 
        //bind to scroll function
        $(document).scroll( function() {
            var hash = window.location.hash
            var hashName = hash.substring(1, hash.length);
            var element;

            //if element has this id then scroll to it
            if ($(hash).length != 0) {
                element = $(hash);
            }
            //catch cases of links that use anchor name
            else if ($('a[name="' + hashName + '"]').length != 0)
            {
                //just use the first one in case there are multiples
                element = $('a[name="' + hashName + '"]:first');
            }

            //if we have a target then go to it
            if (element != undefined) {
                window.scrollTo(0, element.position().top);
            }
            //unbind the scroll event
            $(document).unbind("scroll");
        });
    }

});
mrtsherman
  • 39,342
  • 23
  • 87
  • 111
  • One use case I am thinking of that should be accounted for is if user scrolls the page before automatic scrolling occurs. As I recall the automatic scrolling only happens after the page has completely loaded. If user scrolls before then the autoscroll is canceled. So you would need some way to distinguish between user initiated scroll and browser initiated. I don't know how to do this, but as I recall it is possible. – mrtsherman Aug 12 '11 at 05:12
  • 1
    Booyah! This was a fun late night problem. I'm telling my boss it's your fault when I fall asleep at my desk though. I just made a quick change to remove the return statement. This interfered with the unbinding I added for the scroll event. – mrtsherman Aug 12 '11 at 05:35
  • Initially I got this working within a small basic example file to check it out. Once I confirmed that it did work I was baffled to how it wasn't working within my project. Through process-of-elimination I managed to find a single style declaration in my css file that was causing it to fault. It was the application of an external font. I wrapped your code in a function and am now passing it into a $(window).load() handler within the doc.ready handler. It seams to work now (with a slight initial page flicker). Thanks for the code! Let me know if this is a solid fix or not. – ThomasReggi Aug 12 '11 at 07:23
  • 1
    It won't work if you have content that loads after page loads; Ex: having 2 div that will be filled from ajax with banners. – Decebal Jan 15 '13 at 13:45
  • @FlashThunder - can you define "doesn't work"? Post a console message? – mrtsherman Jun 21 '16 at 15:13
  • @mrtsherman does not change a thing ... Chrome still scrolls to last place on reload. – Flash Thunder Jun 21 '16 at 15:20
  • @FlashThunder - thanks Flash. This must have worked previously because Chrome is my *goto* browser. I'll update my answer based on josetapadas answer. Apparently Chrome requires that you bind to a different event now. Thanks again. – mrtsherman Jun 24 '16 at 19:47
  • @FlashThunder - actually, I don't know if there is a way to modify this answer. jose's answer is the new, correct way to do this. I'll simply make a note in my answer and leave my solution up here for reference. – mrtsherman Jun 24 '16 at 19:50
4

This works for me.

    //Reset scroll top

    history.scrollRestoration = "manual"

    $(window).on('beforeunload', function(){
          $(window).scrollTop(0);
    });
Pedro Mutter
  • 1,178
  • 1
  • 13
  • 18
Alex Having Fun
  • 430
  • 4
  • 5
3

Here's a a more general approach. Instead of trying to prevent the browser from scrolling (or jumping to the top as it would look like) I just restore the previous position on the page. I.e. I'm recording the current y-offset of the page in localStorage and scroll to this position once the page has loaded.

function storePagePosition() {
  var page_y = window.pageYOffset;
  localStorage.setItem("page_y", page_y);
}


window.addEventListener("scroll", storePagePosition);


var currentPageY;

try {
  currentPageY = localStorage.getItem("page_y");

  if (currentPageY === undefined) {
    localStorage.setItem("page_y") = 0;
  }

  window.scrollTo( 0, currentPageY );
} catch (e) {
    // no localStorage available
}
Oliver Schafeld
  • 17,358
  • 2
  • 15
  • 13
2

You can just put a # at the end so the page will load at the top.

Works on all browsers, mobile and desktop, because it is so simple.

$(document).ready(function() {
var url = window.location.href;
console.log(url);
if( url.indexOf('#') < 0 ) {
    window.location.replace(url + "#");
} else {
    window.location.replace(url);
}

});

// This loads the page with a # at the end.

Daut
  • 2,537
  • 1
  • 19
  • 32
0

this works absolutely fine. Nice and clean javascript

    var objDiv = document.getElementById("chatbox");
if ( window.history.replaceState ) {
  objDiv.scrollTop = objDiv.scrollHeight;

    window.history.replaceState( null, null, window.location.href );
}
Magdi T.
  • 1
  • 2
-2

You should be able to.

Onload, check if window.location.hash has a value. If it does, grab the element with an id that matches the hash value. Find the position of the element (recursive calls to offsetTop/offsetLeft) and then pass those values into the window.scrollTo(x, y) method.

This should scroll the page to the desired element.

Natalie Hedström
  • 2,607
  • 3
  • 25
  • 36
nikmd23
  • 9,095
  • 4
  • 42
  • 57