Skip to content

The State of the HTML5 History API

Kevin Suttle edited this page Oct 14, 2013 · 17 revisions

Introduction

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.

Browser Implementations

Adoption

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.

Coherence

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

Using It

Basic Usage

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
}

Ajax Usage

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

Problems & Solutions

The Problems

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._

The Solutions

Given those problems, what are the solutions? There are two:

  1. Give up on the HTML5 History API and cry.
  2. 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

The Future

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 :)

The End

Here are the author's details if you'd like to get in touch - he LOVES feedback! So please do get in touch.

Benjamin Lupton

Like it. Share it.

Sharing is by far the most valuable exercise you can do! Here are some pre-made tweets for you:

Further Reading

Licensing

Copyright 2011 Benjamin Arthur Lupton Licensed under the Attribution-ShareAlike 3.0 Australia (CC BY-SA 3.0)