28

Using JavaScript, is there a way to update window.location.hash without scrolling the web page?

I have clickable title elements that toggle the visibility of a div directly beneath them. I want the /foo#bar in the history when clicking titles but don't want the page scrolling about. So when navigating away from /foo#bar I'll be able to use the back button and have the div whose ID is in window.location.hash be visible upon return.

Is this behavior possible?

Jonathon Watney
  • 20,248
  • 9
  • 38
  • 40
  • See [this stackoverflow question](http://stackoverflow.com/questions/568719/is-monitoring-location-hash-a-solution-for-history-in-xhr-apps) and/or [this page](http://www.nicon.nl/hash2history/) where I present a basic script to address the problem. – KooiInc Mar 14 '09 at 08:54
  • Thanks. I've checked out that question and your custom script. – Jonathon Watney Mar 16 '09 at 20:04

6 Answers6

60

To change the hash without having the page reload/scroll, you can now simply use html5 history.pushState.

history.pushState(null,null,'#hashexample');

It's supported by all the major browsers:

http://caniuse.com/history

MDN:

https://developer.mozilla.org/en-US/docs/Web/Guide/API/DOM/Manipulating_the_browser_history#The_pushState().C2.A0method

Also note that the last url parameter we're using here can be any url, so it's not limited to hashes.

Luca Reghellin
  • 7,426
  • 12
  • 73
  • 118
30

As easy as it get

var scrollmem = $('html,body').scrollTop();
window.location.hash = hash;
$('html,body').scrollTop(scrollmem);
Jeff Davis
  • 4,736
  • 4
  • 38
  • 44
Catherine
  • 309
  • 3
  • 2
  • 2
    I think the first line should be "var scrollmem = $('html,body').scrollTop();" to match the third one. Otherwise it doesn't work for me in firefox. – Anthony May 13 '13 at 15:37
  • @Anthony is right not working in firefox Sunny function works well – Amir Bar Dec 18 '13 at 12:17
22

Another thing you could try is changing the id of the element the hash points to temporarily. Worked for me!

function changeHashWithoutScrolling(hash) {
  const id = hash.replace(/^.*#/, "")
  const elem = document.getElementById(id)
  if (elem) {
    elem.id = id + "-tmp"
    window.location.hash = hash
    elem.id = id
  }
}
Sunny
  • 5,825
  • 2
  • 31
  • 41
3

Based on the answer from Sunny I made this function that also avoids undefined and nulls:

    function changeHashWithoutScrolling(hash) {
        var id;
        var elem;

        id = hash.replace(/^.*#/, '');

        if (id) {
            elem = document.getElementById(id);

            if (elem) {
                elem.id = id + '-tmp';
                window.location.hash = hash;
                elem.id = id;
            }
        }
    }
tobias47n9e
  • 2,233
  • 3
  • 28
  • 54
3

This behavior is very much possible. You should look into some of the libraries that have been developed to give you this functionality.

Really Simple History: http://code.google.com/p/reallysimplehistory/ SWFAddress: http://www.asual.com/swfaddress/

Willem
  • 1,094
  • 1
  • 12
  • 23
  • Great. Those look good except for the existent documentation for RSH. I think SWFAddress looks like the best option for now. – Jonathon Watney Mar 16 '09 at 20:06
  • Indeed. I feel that there is a lack of documentation of RSH. I use SWFAddress and so far it has worked just fine. – Willem Mar 18 '09 at 00:25
  • 2
    @shruggernaut In '09 when this answer was written this was much preferable over writing it yourself. Browser support was very scattered and this library allowed you to focus on creating your product instead of creating a library yourself (which was needed at the time to achieve this functionality). That said, I think Stackoverflow should outdate answers at some point. Especially for a fast moving platform such as browsers. – Willem May 18 '16 at 13:22
2

Wanted to add a comment to Catherines answer but I don't have the rep yet -

Great solution however it wasn't working for me in Chrome as $('html').scrollTop() always returns 0 - a minor edit resolves the issue:

scrollmem = $('html').scrollTop() || $('body').scrollTop();
window.location.hash = hash;
$('html,body').scrollTop(scrollmem);
Brian
  • 2,822
  • 1
  • 16
  • 19