javascript – How can I remove the location hash without causing the page to scroll? -ThrowExceptions

Exception or error:

Is it possible to remove the hash from window.location without causing the page to jump-scroll to the top? I need to be able to modify the hash without causing any jumps.

I have this:

$('<a href="#123">').text('link').click(function(e) {
  e.preventDefault();
  window.location.hash = this.hash;
}).appendTo('body');

$('<a href="#">').text('unlink').click(function(e) {
  e.preventDefault();
  window.location.hash = '';
}).appendTo('body');

See live example here: http://jsbin.com/asobi

When the user clicks ‘link‘ the hash tag is modified without any page jumps, so that’s working fine.

But when the user clicks ‘unlink‘ the has tag is removed and the page scroll-jumps to the top. I need to remove the hash without this side-effect.

How to solve:

I believe if you just put in a dummy hash it won’t scroll as there is no match to scroll to.

<a href="#A4J2S9F7">No jumping</a>

or

<a href="#_">No jumping</a>

"#" by itself is equivalent to "_top" thus causes a scroll to the top of the page

###

I use the following on a few sites, NO PAGE JUMPS!

Nice clean address bar for HTML5 friendly browsers, and just a # for older browsers.

$('#logo a').click(function(e){
    window.location.hash = ''; // for older browsers, leaves a # behind
    history.pushState('', document.title, window.location.pathname); // nice and clean
    e.preventDefault(); // no page reload
});

###

window.location’s hash property is stupid in a couple of ways. This is one of them; the other is that is has different get and set values:

window.location.hash = "hello";  // url now reads *.com#hello
alert(window.location.hash);   // shows "#hello", which is NOT what I set.
window.location.hash = window.location.hash; // url now reads *.com##hello

Note that setting the hash property to ” removes the hash mark too; that’s what redirects the page. To set the value of the hash part of the url to ”, leaving the hash mark and therefore not refreshing, write this:

window.location.href = window.location.href.replace(/#.*$/, '#');

There is no way to completely remove the hash mark once set without refreshing the page.

UPDATE 2012:

As Blazemonger and thinkdj have pointed out, technology has improved. Some browsers do allow you to clear that hashtag, but some do not. To support both, try something like:

if ( window.history && window.history.pushState ) { 
    window.history.pushState('', '', window.location.pathname) 
} else { 
    window.location.href = window.location.href.replace(/#.*$/, '#'); 
}

###

This is an old post but I wanted to share my solution
All the links in my project that being handled by JS are having href=”#_js” attribute (or whatever name you want to use for that purposes only), and on page initialization I do:

$('body').on('click.a[href="#_js"]', function() {
    return false;
});

That’ll do the trick

###

Setting window.location.hash to empty or non-existing anchor name, will always force the page to jump to top. The only way to prevent this is to grab the scroll position of the window and set it to that position again after the hash change.

This will also force a repaint of the page (cant avoid it), though since it’s executed in a single js process, it won’t jump up/down (theoretically).

$('<a href="#123">').text('link').click(function(e) {
    e.preventDefault();
    window.location.hash = this.hash;
}).appendTo('body');

$('<a href="#">').text('unlink').click(function(e) {
    e.preventDefault();
    var pos = $(window).scrollTop(); // get scroll position
    window.location.hash = '';
    $(window).scrollTop(pos); // set scroll position back
}).appendTo('body');

Hope this helps.

###

I’m not sure if this produces the desired outcome, give it a shot:

$('<a href="#">').text('unlink').click(function(e) {
    e.preventDefault();
    var st = parseInt($(window).scrollTop())
    window.location.hash = '';
    $('html,body').css( { scrollTop: st });  
});

Basically save the scroll offset and restore it after assigning the empty hash.

###

Have you tried return false; in the event handler? jQuery does something special when you do that, similar to, but AFAIK more impactful, than e.preventDefault.

###

Hope this helps

html

<div class="tabs">
  <ul>
    <li><a href="#content1">Tab 1</a></li>
    <li><a href="#content2">Tab 2</a></li>
    <li><a href="#content3">Tab 3</a></li>
  </ul>
</div>
<div class="content content1">
    <p>1. Content goes here</p>
</div>
<div class="content content2">
    <p>2. Content goes here</p>
</div>
<div class="content content3">
    <p>3. Content goes here</p>
</div>

js

function tabs(){
  $(".content").hide();

  if (location.hash !== "") {
    $('.tabs ul li:has(a[href="' + location.hash + '"])').addClass("active");
    var hash = window.location.hash.substr(1);
    var contentClass = "." + hash;
    $(contentClass).fadeIn();
  } else {
    $(".tabs ul li").first().addClass("active");
    $('.tabs').next().css("display", "block");
  }
}
tabs();

$(".tabs ul li").click(function(e) {
  $(".tabs ul li").removeAttr("class");
  $(this).addClass("active");
  $(".content").hide();
  var contentClass = "." + $(this).find("a").attr("href").substr(1);
  $(contentClass).fadeIn();
  window.location.hash = $(this).find("a").attr("href");
  e.preventDefault();
  return false;
});

URL without any hash.
http://output.jsbin.com/tojeja

URL with hashtag that does not jumping to anchor.
http://output.jsbin.com/tojeja#content1

Leave a Reply

Your email address will not be published. Required fields are marked *