What are the differences between history.pushState & location.hash? [closed]
Asked Answered
S

9

40

I want to update the URL using window.location.hash or history.pushState.

What are the differences and advantages of each method?

Swint answered 18/2, 2012 at 9:37 Comment(0)
R
33

location.hash has a better support than the history.pushState method.

The advantage of the pushState method is that you can bind a state to the history entry.

If you don't need this state object, I recommend to use the location.hash property, to have better compatibility with older browsers.

location.hash = 'new-hash';
console.log(history.state); // null or undefined

history.pushState({extraData: "some state info"}, '', 'new-hash'); //<---
console.log(history.state); // [object Object] = {"extraData": "some state info"}
Runyon answered 18/2, 2012 at 9:40 Comment(7)
But is it possible to bookmark a history.state or to post it on facebook? I think it's possible with hashes. They're completely different things.Christadelphian
@Christadelphian When you bookmark something, the URL as currently seen in the browser is used. The state object is associated with a history entry. And such, it is only available when one navigates to the page by browsing the history (and e.g. session restore after a browser shutdown). One method does not exclude the other one: It's legal to use history.pushState('some long state cached from server', '', '/posts/id#prefix-some-specific-identifier'), for example, if the application really requires it. In this example, a server response is cached. The hash could also have been a slash, by the way.Runyon
Ah, of course. So your answer really boils it down. hash has better support while pushState is more powerful.Christadelphian
After 3 years since this question , which one is better now , pushstate or location.hash ?Furred
@Furred history.pushState or history.replaceState and using history.state if you truly need to associate data with the history entry. If you want the page state to be bookmarkable, then location.hash is sufficient (because a bookmark can only store the page URL, not the history state).Runyon
@Rob W , I'd like to create ajax form search and displaying results without reload page and it will be an ajax pagination also , wich one choose ? ThanksFurred
@Furred location.hash suffices.Runyon
D
29

Pushstate is the future. It's better because:

  1. It looks cleaner.
  2. On revisit of a deep link you can actually surface real serverside data to support things like SEO and Facebook Open Graph (both send spiders to scrape the html of your page).
  3. Servers don't have access to hash tags data so you don't see it in your server logs so it helps some with analytics.
  4. It helps fix hash tag issues. For example I had an Nginx rewrite to redirect users visiting my app to the same https url. It works in all browsers but Safari which will redirect you to just the domain without the hash (so annoying)!
  5. You can actually use hash tag for what is was meant for, deep linking to sections of long pages.
  6. You can fallback to using real HTTP backend requests for browser that don't support push state OR you can fallback to using hash tag. Both require extra implementation but are easily doable with a little work.

See this talk from Github designer for more: http://warpspire.com/talks/responsive/

Devoid answered 18/5, 2012 at 6:38 Comment(11)
Pushstate has a slight disadvantage though: It forces the server to render the page for you upon the first visit / when you open a link page in a new tab. If a person is opening 10s of tabs (Say, browsing a Gallery and opening interesting pictures), it's considerably slower than hashbangs because ajax is not used at all.Catrinacatriona
@Hello-World: That is an assumption. For many/most JavaScript-based frameworks it's doing the exact same thing that hashbangs would have.Devoid
Can you please explain? suppose I visit example.com/ajax#gallery , my browser downloads some js through example.com/ajax and then that js requests and renders #gallery. When I open example.com/ajax#image1 in a new tab, my browser has already cached example.com/ajax so it only needs to fetch #image1 and render it. As far as I can see, this is not the case with Pushstate. When you open example.com/ajax/image1 (pushstate) in a new tab or visit it for the first time, the browser has to download a full page regardless of the cache at example.com/ajax. If I'm wrong, I'm open for correction.Catrinacatriona
@Hello World: Ok you are technically right. Generally when pushstate is being used it changes the URL dynamically and no extra page load is done. If you right click and open a link in tabs you are not really utilizing the whole point of dynamic pushstating. Click an image in your Facebook stream, note the dynamic URL change, and then paste the URL in a new window. What you just saw is way more advantageous than the "disadvantage" you mention. In this case it's actually a bonus not a disadvantage.Devoid
(Context: In Facebook, the gallery is ajax based, clicking a photo changes the URL and enlarges that photo, copying the URL to a new tab loads a static page of the photo). This is not more advantageous. Consider this alternative: Gallery is at fb.com/#gallery-17 . Clicking a photo enlarges the photo and changes url to fb.com/#photo-521. That is far more efficient when opening multiple photos because fb.com is always cached.Catrinacatriona
Also, opening fb.com/#photo-521 for the first time/in a new tab would just load that photo without any regard to the gallery.Catrinacatriona
fb.com/#gallery-17 is a hack and doesn't support SEO (web servers can't even see the hash tag in the server logs). fb.com/gallery-17 is a legitimate address for a resource item. If a user goes to fb.com/galleries/#gallery-17 depending on how its architected the user could be fetching more content than was necessary (list of galleries). Hashtag hack can be just as "wasteful" as pushstate. CURL, WGET, and other tools can't even fetch hashtag specific resources. Hash tag was meant to scroll down the page to a resource. It was never meant for the hacky stuff we are now growing out of.Devoid
Additionally fb.com/#gallery-17 is slower than fb.com/gallery-17 as the whole page and its content needs to load then an ajax call needs to be made and loaded in to the page for the right content - as apposed to just showing the right content. Pushstate is the future because in the case of FB stream you popup a picture and keep your context behind it but if you want to bookmark that URL you go directly to the resource that you bookmarked. If you saved a hashstated URL then it loads content you don't need before the resource you want loads. Think about it. Leaving the discussion now.Devoid
SEO can be supported with hashbangs. fb.com/#gallery-17 is slower indeed, but new tabs with hash/hasbangs are faster. Regarding CURL and WGET, that's totally true. I am not saying hashbangs are a holy grail, I only stated an advantage.Catrinacatriona
I made a relevant question here: webmasters.stackexchange.com/questions/65694/…Catrinacatriona
Suppose I have a single-page application with no dynamic backend (basically, the app is just a static index.html file plus the JS machinery). If I understand well, I can't use pushState in this situation because the server is unable to respond to the URLs that describe the application state. In that situation, I'm obliged to use location hash. Am I understanding correctly?Yaws
B
20

This is a rather old question (5 years+ at the time of this reply) but a lot of comments on existing replies are asking for an update based on the "current" state of things.

Here's the deal:

HTML5's pushState is supported on all major browsers. If you are supporting older browsers too, history.js provides a great polyfill that lets you use pushState natively and have it easily fall back to legacy URLs for older browsers. Now that pushState is natively supported does not mean, however, that it is definitively the way to go.

There is a very important point that was not raised in any of the older answers and that is that hash URLs and pushState URLs are not only different in the way they appear, but they are actually different in the way they work, too. This fundamental difference between the two might lead you to choose one over the other.

pushState is prettier and cleaner and can be used to completely fake navigation on your site/in your app. For example, GitHub uses it to replace all navigation invisibly. When you click any link on their site, javascript is used to intercept that click and turn it into an AJAX request that updates the contents of the page without loading a new page, while the URL in the location bar changes to match the content that was fetched. This is what pushState was meant to be used for.

In GitHub's case, http://mysite/page1 and http://mysite/page2 are both valid URLs. They are "real" links with "real" content, and initially visiting either page goes through the traditional MVC approach. GitHub uses pushState for navigation in modern browsers, but does not require it - i.e. pushState is used as a "feature add" to (in their opinion) lead to a better user experience when it comes to navigation. When you copy the link in the browser address bar, you are copying a link that was formed via javascript & pushState, but a link that is nevertheless real and valid.

However, if you are starting from scratching and creating a single page app and are not using an MVC framework, chances are that you actually only have a single page, especially if you are not using a dynamic backend (i.e. content is all retrieved via javascript, never generated by a server). In this case, if you use pushState over hash urls, you will need to handle the case that the URL in the browser is not the real URL. I will illustrate.

The user loads your single page app: http://mysite/mainpage

At this point, the browser bar contains the real link to your app, and will take the user to the same view they currently see: the main page. Now they click a link that will take them to a "page" showing the details of some activity. At this point, you want to update the location bar to indicate the change in state. You either use a hash URL and your location bar looks like http://mysite/mainpage#charts/1 or you use pushState and trick it to becoming http://mysite/mainpage/charts/1

If you used pushState, that is not a real link. Navigating via the browser's back/forward buttons will work great and the user will go from the main page to the detail page in both the location bar and in the app (presuming you handle the state change correctly), but if the user bookmarks this link or copies and pastes the link to share it, additional server-side voodoo will be required.

You will need to redirect requests to /mainpage/charts/1 to /mainpage and then use JS to resolve the actual URL and carry out the intended state change operation. A server redirect is absolutely required. You cannot host this page on AWS or on your local disk without a scriptable http server.

Now if you used hash urls, your URL that the user would have seen and interacted with would have been http://mysite/mainpage#/charts/1 and that is a valid, real url. Browsers understand that there is just one page, and whether the user copies and pastes the link or bookmarks it, you just have to handle the hash state in javascript and do not need any server-side magic to make things work.

What no one seems to mention is that pushState and hash links are not mutually exclusive. pushState is just an API to manipulate the browser location that is visible to the user and implement reliable back/forward navigation in modern browsers. It says nothing about what your URL scheme should look like.

In 2017, Google and just about every other JS-capable bot understand hash URLs and traverse them just fine. Google wants you to use the #! abomination for SEO maximization purposes, but even if you don't, your site will be navigable just fine.

The correct answer is to use whatever fits your needs best. If you have real URLs and want to fake navigation between them, use pushState and carry on (optionally with a polyfill for older browsers). But if you have a single-page app, don't pretend not to (unless you have a very good reason). Use hash URLs to make your life easier and not introduce unnecessary problems and then use pushState to manipulate those hash URLs to take advantage of better back/forward support.

Bonedry answered 30/6, 2017 at 15:30 Comment(3)
I'm not sure what you mean with the last sentence: are you suggesting to replace URL with location.hash and then do it again with pushState? How would that help? From what I understand the main issue with pushState is bookmarking, but if we were to do this wouldn't we end up with bookmarked URL that requires redirection magic anyway? BTW, extremely clear and informative, trying to get all this info felt like composing a difficult puzzle, and here you really touched almost everything related to the discussion, thanksCheetah
@FabioLolli in regards to the last sentence - In my apps I sometimes find myself manipulating the location hash via pushState and replaceState. For example a recent app performed searching on keypress. This searching should update the URL for bookmarking/forwarding etc. but you wouldn't want each keystroke to fill up the history stack with a new entry (as would happen by just manipulating location.hash). Instead I use replaceState while typing then after some debounce timeout or hitting the enter key do a pushState if necessary.Bernhard
Actually, as of Oct. 2015 Google does NOT want you to use #!. webmasters.googleblog.com/2015/10/…Jevon
N
14

history.pushState is better than location.hash. but it is a HTML5 feature. so always better to have a fallback method like below.

if (typeof(window.history.pushState) == 'function') {
    window.history.pushState(null, path, path);
} else {
    window.location.hash = '#!' + path;
}
Neau answered 18/2, 2012 at 9:42 Comment(2)
After 3 years since this question , which one is better now , pushstate or location.hash ?Furred
A fallback makes no sense here: location.hash will work just as well on browsers that also support pushState - and if you actually needed pushState (because you needed to store an object) then location.hash wouldn’t work as a fallback. Just pick one.Erena
S
10

I agree with the other answers, but here are a few arguments in favor of location.hash:

  • it works in every browser, including Internet ExploderTM
  • history.pushState is a developing standard, and the API may change in the future
  • if the users opens a link in a new window/tab, a hash-URL makes sure there is no server request needed to load the page (if the correct caching headers are set)
  • The server configuration is easy, since all the server ever sees is the URL without hash-part

edit: I forgot one

  • with hashtags, you can use real links (a href). So you don't have to set up click listeners, which improves performance and reduces code size.
Springtime answered 8/7, 2012 at 11:54 Comment(2)
Google will send #! based hashes... which requires a bit of effort... did this for photogallery.classiccars.comKandykane
Are there any plans to make Pushstate better with new tabs?Catrinacatriona
A
7

The advantages/disadvantages of window.location.hash vs HTML5 history.pushstate are largely determined by how exactly you want your page to degrade.

Here, you might be interested in graceful degradation in two different scenarios :

The first one being a client which does not have javascript enabled, or an automated bot/crawler visiting your site. This is particularly important from an SEO perspective. If your web-page/web-application uses hash-urls then content that is available through these links is not available to these end-users. This is definitively a problem if you are making sections of content available only via hash-urls with no fallbacks. However it is definitely not a problem if you are using hash-tag links to modify application state which simply don't retain meaning if the page degrades.

As an example consider a scenario where you have a page with three sections of text available in three tabs in a tabbed-layout widget. Now there are two possible scenarios : In the first, you would be loading all the content during the page load - and the tabbed widget will simply serve to hide other sections and show a particular section. So if you use hash-urls in the links you use to construct the tab thumbs, you are using them only to change the client-side application state. When javascript is turned off/is not available, simply the javascript used to construct the tabbed layout does not run, and all the content is immediately available - a reasonable graceful fallback. The different application states simply don't exist in this case and so the hash-urls degrade back to just pointing to anchors in html - the intended purpose. Instead of hash-urls if you were to use html5 pushstate in this case, it would be a bad idea. The reason if that a user might bookmark the link to a particular tab. Because your server would have to take that url and present the user with the client side state which he is expecting. This is not good for a thin server architecture where the client-side should take care of its own state management. You can ofcourse ignore that aspect on server side and let the client check the url right at the beginning upon page load and then switch to appropriate application state. But still it is not a good idea because your server side routing system is concerned with the overhead of additional url fragments which it should ignore, where as it should not be bothered about that fragment at all from an aesthetic perspective. This maps exactly to the requirement for which hash-urls were designed and using them is strongly recommended. If instead in the three sections, the text gets loaded dynamically when a particular tab thumb is clicked, then using hash-urls is not a good idea. The reason being the user will simply have no way to access the linked content if javascript is not available. This is particularly bad for SEO. In this scenario if you handle urls (which would in normal scenario be "hijacked" and "ajaxified") on the server side to make content available in general it is excellent both from point of view of end-user experience as well as SEO.

The second scenario is a client who has an antiquated browser which does not support html5 pushstates. While the above points still hold, in addition I would also argue that forcing users with no pushstate with the same level of degradation as no-javascript is not justifiable. A lot of end-users will simply have no idea why they are receiving a degraded version.

I would recommend you not to tag along with dogmatic motivation of using the latest technology always, and decide the best option for your usage scenario.

Acoustic answered 9/7, 2012 at 9:57 Comment(1)
good answer, but I don't quite agree with the SEO part. You can use hash-urls and still have your page indexed. See developers.google.com/webmasters/ajax-crawlingSpringtime
C
2

Currently, pushState is supported by all modern browsers. Therefore pushState is better than location.hash, but it is a HTML5 feature.

So, location.hash is not dead, in fact it will be around for a long, long time.

A good way to use this is with a lib that supports pushState, but also gracefully degrades to using location.hash.
Example - https://github.com/browserstate/history.js

Moreover location.hash will still be useful for jumping to named anchors. pushState will be a tremendous help in building web apps. I look forward to using it.

Constantin answered 14/7, 2012 at 14:32 Comment(0)
P
1

I personally prefer pushState because it makes nicer looking URLs and I think that is important for user experience.

You can use history.pushState with a hash fallback using the history.js polyfill if you want to use pushState, but don't want to have issues with older browser support.

Pavis answered 14/7, 2012 at 8:46 Comment(1)
Your user experience is determined by a # which most users do not even notice?Lycurgus
A
0

One very small difference I don't see noted anywhere in this thread:

Setting window.location.hash will force an immediate scroll jump to the new hash element in the document (at least in the browsers I have). If you want a smooth scroll but also want the hash in the url bar to update/change, you'll have to use window.history.pushState like this:

document.getElementById(id).scrollIntoView({ behavior: "smooth" });
window.history.pushState(null, null, "#" + id);
Algol answered 19/6, 2021 at 21:0 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.