The State of the HTML5 History API
The HTML5 History API is hugely important as it finally allows us to create stateful web sites.
This works by pushing or replacing states via history.pushState(data,title,url)
and history.replaceState(data,title,url)
respectively.
-
data
: is a json object (optional) -
title
: is the title of the state (optional) -
url
: is the url of the state
Before the HTML5 History API we had to implement hacking workarounds such as transforming the traditional anchor in a url, into a stateful hash. Which caused and is still causing the web to break for search engines and javascript disabled users for websites which implement the hash workaround.
The HTML5 History API should provide us with a way forward, but it does still have its problems which libraries such as History.js attempt to resolve.
The HTML5 History API adoption rate has been very quick by browser vendors. It is currently supported by the following browsers:
- Firefox 4+
- Google Chrome
- Internet Explorer 10+
- Safari 5+
- iOS 4
However, just because those browsers have implemented the HTML5 History API, the functionality of it is incoherent across all implementations. Which is a serious problem.
Note: Each Yes/No should also be accompanied with the version which this happens in. As a few changes have occurred throughout the versions. Ideally, having an automated test suite to detect these differences would be the bomb, though some of these differences do require manual testing, alas an automatic test suite will really speed things up.
Firefox | Chrome | Safari | iOS | Opera | IE | History.js | |
---|---|---|---|---|---|---|---|
Minimum Working Version | 4 | 8 | 5.0 | 4.3 | 11.5 | 10 | 1.7 |
Supports onpopstate
|
4+ | 8+ | 5+ | 4.2+ | 11.5+ | 10+ | onstatechange |
Supports onhashchange
|
3.6+ | 1+ | 5+ | 4.0+ | 8+ | 8+ | onanchorchange |
Initial onpopstate
|
No | Yes | No | No | No | No | No |
Initial onhashchange without a hash in the url |
No | No | No | No | No | No | No |
Initial onhashchange with a hash in the url |
No | No | No | No | No | No | No |
Fires onpopstate with hash changes |
Yes | Yes | No | No | No | ? | Only on state changes |
Fires onhashchange with hash changes |
Yes | Yes | No | No | Yes | Yes | Only on anchor changes |
States still set when busy | Yes | Yes | Yes | Yes | 11.5+ (before hashes would fail to apply) | ? | Yes |
States still fire when busy report | Yes | Yes | 5.1+ | No | 11.5+ (before hashes would fail to apply) | ? | Yes |
Can replace a hashed url report | Yes | Yes | 5.1+ | No | Yes | Yes | Yes |
Back buttons work with new states | Yes | Yes | Yes | 4.3+ | Yes | ? | Yes |
back/forward/bookmark/etc will trigger onpopstate
|
Yes | Yes | Yes | Yes | Yes | Yes | Yes |
pushState and replaceState will trigger onpopstate
|
No | No | No | No | No | ? | Yes |
pushState and replaceState will set document.title
|
No | No | No | No | No | ? | Yes |
State data persists when navigated away and back | ? | One state only | ? | ? | ? | ? | Optional |
Transparent HTML4 Fallback | No | No | No | No | No | No | Optional |
The HTML5 History API in its most basic form is expected to be used like so
var myNewState = {
data: {
a: 1,
b: 2
},
title: 'My New State',
url: 'my-new-state.html'
};
history.pushState(myNewState.data, myNewState.title, myNewState.url);
window.onpopstate = function(event){
console.log(event.state); // will be our state data, so myNewState.data
}
Now say we want to ajaxify our entire website, we'll actually end up with a fair few lines of code as there are a lot of things we have to take into consideration. Because of this, the code snippet and explanation for ajax usage has been abstracted from this article and you can find it by clicking here
Now that we have our entire website ajaxified, it should be a time for celebration. However, due to the incoherence of browser implementations we're going to quickly start discovering some problems.
Look back at the table before and think about how each of the different behaviours will affect our code snippet. The most obvious ones are:
- In Safari, iOS and Opera as we are loading in our content via AJAX the browser will fail to set and/or create our state history entries, making navigating our ajax website impossible
- In Google Chrome the initial page load will cause our content to load in twice
Which can you come up with? If you're starting to think the HTML5 History API isn't as feasible as you first thought, if not entirely impossible to use natively - then you'd be right._
Given those problems, what are the solutions? There are two:
- Give up on the HTML5 History API and cry.
- Code a series of hacks and workarounds to try and provide a coherant interface for the HTML5 History API
Luckily, fortunately, blissfully, someone figured the HTML5 History API was too darn important to give up on and decided to pursue option 2. The result is Benjamin Lupton's History.js - so thankyou Benjamin!
Click here to see the earlier ajax usage code snippet updated for History.js
Click here to try that updated code snippet with History.js on a real website
History.js is as stable as it gets right now. The future is with improved documentation, education, and extensions and frameworks surrounding it - such as integrations with other content management systems. They are all under active development by Benjamin Lupton but he can always do with your help. If you'd like to help in any way (even if you're not sure how you can help out) then please do get in contact with him - his details are in the footer :)
Here are the author's details if you'd like to get in touch - he LOVES feedback! So please do get in touch.
- Email: b@lupton.cc
- Skype: balupton
- Website
- Google+
Sharing is by far the most valuable exercise you can do! Here are some pre-made tweets for you:
- The current state of the HTML5 History API across the different browsers, and why we need History.js - https://github.com/browserstate/history.js/wiki/The-State-of-the-HTML5-History-API
- The state of the HTML5 History API and why it isn't good enough - https://github.com/browserstate/history.js/wiki/The-State-of-the-HTML5-History-API
- The History.js Readme: Your guide to History.js
- Intelligent State Handling: The evolution from hashes, to hashbangs to the HTML5 History API
Copyright 2011 Benjamin Arthur Lupton Licensed under the Attribution-ShareAlike 3.0 Australia (CC BY-SA 3.0)