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

Solution 1:

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"}

Solution 2:

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/

Solution 3:

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.