Zachary Johnson — @zacharyjohnson
Zachstronaut LLC — zachstronaut.com
The History API can fix UX problems in your client-side JavaScript web applications and UI patterns.
Then, we'll see what the History API is and how it can fix these problems.
Since "AJAX" we've been able to create complete multiple-view experiences in the browser without ever having to leave the current page or change URL.
If your entire web site experience happens on a single URL, then you've just broken your users' browsers.
URL should represent current view / UI state / data loaded in view.
create amazing web UI that feels like "native" UI. (I <3 Google Docs, and I <3 JavaScript!)
break my browser!
(When you forget this you create problems for your users.)
Coming soon to the AppStore
Facebook, Twitter, Pinterest, and most sites using infinite scroll append new content to their main view but never change URL.
Auto-fetching the next page is awesome.
Breaking the browser is not.
/iˈpitəmē/
1. A person or thing that is a perfect example of a particular quality or type.
Infinite Scroll is the epitome of bad UX.
I'm catching up on my Twitter feed, and infinite scroll has loaded an unknown number of new tweets, and then I click a link that takes me to a new page...
When I press my back button, I start over at the top of my feed.
I especially love it when I've been scrolling and loading for 10 minutes and then my browser crashes.
I'm doing a whole session on fixing the many UX problems with infinite scroll at MinneWebCon.
Speaking of fixing things...
The JavaScript History API lets you update the web browser's location / URL without leaving or reloading the current page. (The full URL, not just the hash.)
Boo! /puppies/#/monsters/frankenurl/
Yay! /monsters/frankenstein/
What if when Infinite Scroll automatically loads page 2, it also automatically changes the browser location to the URL /page/2
?
Then, if I leave from page 74, I can go back to page 74!
Object: window.history
history.pushState(data, title, url)
history.replaceState(data, title, url)
Event: window.onpopstate
window.location.href
also reflects any changes.
Google: MDN History for more docs.
/puppies/#/monsters/frankenurls/
/about/
→ /games/walrus-run/
/about/
→ /about/#/games/walrus-run/
History API was added as part of HTML5 spec.
GitHub: History.js polyfill*
* /hope/you/like/#/polyfills/
So fixing Infinite Scroll was as easy as calling history.replaceState()
with the URL of the next page being AJAX loaded, right?
Ehhhhhh... let's try that and see.
/**
* https://github.com/paulirish/infinite-scroll
* Infinite Scroll Load Success Callback
*/
function (elements, data, url) {
if (window.history) {
// We want to give people the ability to hit back to return to
// home so they can more easily reload for new content at the
// top of the infinite scroll experience
if (window.location.href.match(fixConfig.homePattern)) {
history.pushState('', '', url);
} else {
history.replaceState('', '', url);
}
}
}
(If you use the History API to kill a page's own grandfather...)
** Hey JSMN: Have browsers ever cached pages as-altered by JS? Or has it always been that just the results of the HTTP request response are cached?
When the user presses their back button, they'll go back to the same scroll position but not the same content.
D'oh.
When you load new content, you can change the URL with the History API.
If the user presses Back/Forward, that will also change the URL... but it won't change the content.
When the URL of our app changes, we must manage the view/content state ourselves!
Listen for the window
object's popstate
event:
/**
* Execute immediately or you might miss the first event!
* Don't wait for onload or dom ready!
*/
if (window.history) {
var firstPop = true;
window.addEventListener('popstate', function (e) {
// The first pop happens when this page first loads. If we
// pop again then the vistor is using forward/back within our
// site, so we must update the content accordingly.
if (!firstPop && location.href.match(fixConfig.homePattern)) {
// Scroll to top of homepage, and get latest posts.
setTimeout(function () {window.scrollTo(0, 1);}, 0);
setTimeout(function () {window.location.reload();}, 1);
}
firstPop = false;
}, false);
}
No longer totally b0rked, but still lacking UX finesse
More Infinite Scroll UX improvements coming soon!
I'll post my slides and code after MinneWebCon.
My clients want maximum control over the visual experience of their sites, including during loading and transitions between pages.
They don't want flicker/redraw when a user clicks a link.
Hey JSMN, do any JS frameworks do this for views, ie history and view events? Ember, Angular?
Build your JavaScript app with URLs that point to meaningful UI/view/data states. Use the History API to set those URLs to match your app's state.
Simple Tip: What URLs would your app have if it wasn't AJAX / didn't use JavaScript?
/puppies/#/monsters/frankenurls/
Zachary Johnson — @zacharyjohnson
Zachstronaut LLC — zachstronaut.com
* I've got one for you, JSMN. Is there something better than reveal.js? I want syntax highlighting and the ability to create a file I can upload to SlideShare.