HTML5 History in IE10
By Tony Ross
Building fast and functional sites is a challenge with which most Web developers are familiar. Loading a new page every time the user clicks a link is slow. Fetching all content dynamically effectively disables the back button. Working with hashes is better, but still not ideal. Internet Explorer 10 in the Windows Developer Preview eliminates the compromise by adding support for HTML5 History. The pushState, replaceState, and popstate APIs provide fine-grained control over the behavior of the back button and the URL presented to the user for dynamic content. Together these APIs help you improve the performance of your site without sacrificing usability.
If you’re not already familiar with the HTML5 History APIs, think of pushState as being the dynamic equivalent of navigating to another page. Similarly, replaceState is much like location.replace. The difference is these APIs leave the current page intact when updating the session history by storing states instead of pages. Both pushState and replaceState take three parameters: a data object, a title, and an optional URL.
Note that the title parameter to pushState and replaceState is ignored by most browsers, including IE10. If you want, you can still provide this information since future browsers may expose it as part of their history UI.
Setting Custom URLs
The URL parameter to pushState and replaceState can be used to update the URL of the page without navigating. To illustrate, consider you’ve loaded “http://www.contoso.com/index.html.” Using hash changes, you can only append to the URL:
But with pushState and replaceState you can point to a completely different page on your site without actually going there:
Make sure your server can handle all dynamic URLs you create so things like favorites still work. You can also add some data to the state object so you don’t have to parse the full URL later to restore the state:
The protocol, hostname, and port must match the current URL, but the path, query, and fragment are fair game for customization. This enables associating dynamic states with URLs that are easily backed by the server and work even when script is disabled. Ultimately, this lets you dynamically fetch and display only the data that changes from page to page while keeping the user experience intact.
Restoring Saved States
You should restore state after navigating the history (for example, when the user presses the back button) or reloading the page. Restoring state is accomplished by listening to the popstate event. The popstate event fires when state changes as a result of history navigation. At this point the data object for the destination state can be retrieved via history.state. In cases where the page is reloaded the popstate event will not fire, but history.state can still be accessed at any time during or even after the load. Thus code like the following can restore state at the appropriate times:
Storing Complex, Dynamic Data
To change this to keep track of the current state without tracking each change, you can use replaceState instead of pushState.
HTML5 History makes pushing large amounts of data onto the stack easy if you’re not careful. For example, the undo demo above stores ~0.5MB per state and could easily use more if the canvas was larger. This data will consume memory as long the associated state entry remains in the session history, which can be long after the user leaves your site. The more data you store, the sooner a browser may start clearing your entries out to save space. In addition, some browsers also enforce a hard limit on the amount of data that can be stored with a single call to pushState or replaceState.
As always, use feature detection to handle differences in support across browsers. Since most of HTML5 History involves events and properties, the only new parts that truly require detection are calls to pushState and replaceState:
Such detection will at least keep your script from failing in older browsers. Depending on your scenario, you may want to start with full-page navigations and upgrade to dynamic content when HTML5 History is supported. Alternatively, you can use a history framework or polyfill to keep the back button working, but keep in mind that not everything can be emulated. For example, dynamic control over the path and query components of an URL can only be achieved via pushState and replaceState.
Note that some browsers support an earlier draft of HTML5 History with two notable differences from the current draft:
In order to support these browsers, you can fall back to reading the state information off the popstate event itself.
Overall, the HTML5 History APIs provide a great deal of flexibility for building responsive and usable Web sites. With some care taken for legacy browsers, these APIs can be used today to great effect. Start testing them with your site in IE10 on the Windows Developer Preview and send feedback via Connect.
About the Author
Tony Ross is a Program Manager in the Microsoft Internet Explorer team.