Change URL hash without page jump

In modern complex layouts, sometimes the point where a hash will transport you to will be entirely different than the one you actually wanted. If you prevent the default event, you will save yourself from the page jump, but the hash won’t change either. You can accept the regular behavior and change scrollTop after the jump, but the user will still see a distracting flicker.
Chris Coyier found a great workaround last year but it’s not meant for every case.

A different solution

Turns out we can take advantage of the History API to do that quite easily. It’s just one line of code:

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

and we can combine it with the old method of setting location.hash to cater for older browsers as well:

if(history.pushState) {
    history.pushState(null, null, '#myhash');
else {
    location.hash = '#myhash';

Browser support?

The History API is supported by:

  • Firefox 4+
  • Safari 5+
  • Chrome 8+
  • Coming soon in Opera

Enjoy 🙂

  • Great! 🙂 I’ve been looking for something like this before, good thing I can have it now 😛

  • Adam Taylor

    Nice. Unfortunately, what this doesn’t do is update the page’s CSS pseudo-selectors, so changes to :target selectors don’t seem to fire…

    I’ve been using :target to perform a JS-free hide and show of content, with a close button that links to an empty hash (‘#’). As you’d expect, this causes a page jump too, which I’d prefer not to have, and had hoped your solution would fix… Ah, well.

    (Did that make sense? 🙂 )

    • Aw, that’s so sad 🙁 I guess it won’t fire the hashchange event either 🙁 

      Thanks for the tip! 

    • DekuLink

      I know this post is 3 years old, but I figured I’d post the solution for anyone that comes across this. Surprisingly, the solution involves no javascript. The HTML for each tab looks like this:

      Tab content goes here

      The CSS:
      .tab {display:none;}
      .target {display:block;top:0;left:0;position:fixed;}
      .target:target + div {display:block !important;}

      The span will stay at the top of the viewbox, so when it scrolls to it, it won’t go anywhere. The + operator selects the div that imediately follows the :target-ed span with the “target” class.

      Hope I helped a few people! This solution was tough to find!

      • DekuLink

        Hmmm… Seems that the html didn’t work. It’s supposed to show a span right before the div. It looks like this: span class=”target” id=”tab1″

        I guess the messed it up. :/

      • Darwin

        Setting the position attribute to fixed is what seems to resolve the scrolling issue, but it seems to mess up other styling…

    • Neil Monroe

      4 years later and this is still the case. To state it in slightly different terms, the main issue is that the element that originally had the :target pseudo-selector match on page load will still match even if the hash is updated. Because of this, you may have two tab contents visible at once.

      To make this work correctly, you will have to check the hash in script and update your applied styles that way.

  • If the history API is not supported:
    | var x = pageXOffset, y = pageYOffset;
    | location.hash = ‘#foo’;
    | scrollTo(x,y);
    Have fun

    • What if the hash is changing through anchor links and not through code?

  • Anonymous

    Anchor Tag with class=’JumpToTop’ href=’#id-name’ and a java script$(‘.JumpToTop’).click(function() { var elementClicked = $(this).attr(“href”);  var destination = $(elementClicked).offset().top; $(“html:not(:animated),body:not(:animated)”).animate({ scrollTop: destination-20}, 1000 ); return false;});  
    will do a better work! what say?

  • Thanks for this! I had no idea about the History API. Really helps on AJAX projects.

  • Hello,
    Just to say, it seem to work without the hash for location.hash = ‘myhash’;

  • Pingback: How can I update window.location.hash without jumping the document? - Javascript Solution - Developers Q & A()

  • Tobias Buschor

    a tricky alternative without flickering:

    var el = document.getElementById(‘myhash’);
    var id =;
    location.hash = ‘myhash’;

    • a hero to the people you are, sir.

    • firiz

      Thanks 😉 This is exactly what I want.

    • Andy

      One thousand internets to you sir

    • Thank you for this amazing hack!

  • felix


  • hhaaaa I would like the same on my futur Website ::
    You see, you scroll, the #is-automaticly-added

  • Adam

    Thanks for pointing me in the right direction with this!

    My use case was a little different in that I don’t want the back button to cycle though every tab click, but rather the actual previous page. Look at the W3C spec, (your link is broken btw: I made this instead, hopefully it helps someone looking for the same thing:

    // I.e. replace ‘pushState’ with ‘replaceState’
    if(history.replaceState) {
    history.replaceState(null, null, ‘#’ + hash);
    } else {
    location.hash = ‘#’ + hash;


  • silva

    Thank you so much for this! Saved my life. I love you so much!

  • Thank you, thank you, thank you. This worked perfectly.

    The script you provided solved my problem: a visitor clicks on “Close All”, the text block closes, the screen then jumps to the bottom (without the visitor realizing it) of the page and then to the anchor at the top of the page. Lastly, the hash in the url changes, preventing any issues with how different devices (mobile, tablet) interpret the anchors.

    window.location.hash =”#faq_top”;
    if(history.pushState) {
    history.pushState(null, null, ‘#faq’);
    else {
    location.hash = ‘#faq’;

  • Pingback: angara fahise()

  • Pingback:

  • Pingback: angara fahise()

  • Pingback: angara fahise()

  • Pingback: Daftar Agen Bola Terpercaya()

  • Pingback: Jumpstart your Wealth Gene -

  • Pingback: Opulence for life scam()

  • Pingback:

  • Pingback: Live streaming video()

  • Pingback: prams()

  • Pingback: Term Life Insurance()

  • Pingback: best anabolic steroid()

  • Pingback: Dragon Ball Super Episode 48 English Sub()

  • Pingback: chesterfield sofa()

  • Pingback:

  • Pingback: Lilburn Dui Lawyer()

  • Pingback: swing plane driver()

  • Pingback:

  • Pingback: Live draw hongkong()

  • Pingback: life insurance claim lawyer attorney law firm()

  • Pingback: skypepsyxologmoskvakiev()

  • Pingback: saleforiphone()

  • Erik Povh

    After hours of trying out every solution I could find…. this one acctully worked, thanks a lot!