Today we’re going to look at a way to keep a sense of consistency on your website by maintaining the state of some elements even when the user navigates through history. We’re effectively going to create history-inactive areas which remain in the same state while the rest of the document is navigable.
Background
This technique effectively allows ‘selective’ loading of elements. Effectively, if the user clicks a link or presses the back button, instead of loading the whole page (most of which stays constant, like script and stylesheets), we will only load the stuff that changes, i.e. the content. By doing this we save load times There are two main reasons why you would want to only load certain elements when your user uses the back and forward button to navigate through history. This cuts out all the unnecessaries and creates a faster web experience. There are two main reasons why you would want to do this:
It saves time on loading
Search engines take load time into account when ranking
The web is becoming more mobile and top internet speeds aren’t available everywhere, and hey, not everyone has a dedicated broadband connection, so saving some time on your load speeds is always going to benefit your users. On top of that, search engines take into consideration the speed at which your web page loads when ranking your pages.
By using the History API we cut out all the junk. The styles, scripts and meta tags aren’t really going to change that much (and if they do we can load them in with the content we’re loading using the history API), so we don’t necessarily want to load them again. Using this we just load the stuff we know will change from page to page, the content. This can be done pretty simply by using a little javascript. This will save a lot of time for the user between page loads.
2. Consistency
Soundcloud uses this technique to keep music playing
The web is constantly evolving. Websites are often thought of as linear, single pages connected by links. Recently there has been a movement towards application-like websites. Facebook and many other services are trying to provide an experience that doesn’t feel like a bunch of loosely linked pages but a single, complete application with no gaps.
Using the History API we can sort of move in this direction. Lets take Soundcloud as an example. If you are listening to a song on Soundcloud and press the back button the song keeps playing. On a regular, loosely knitted website, the song would pause or stop as the user travelled through history. Soundcloud provides a unique, linked, experience, simply by using the History API. In our example today we’re going to explain how the History API works and make a Soundcloud-like demo that allows travelling through history while a song continues to play.
How it Works
To make this work we’re going to use a little jQuery and intercept when the user clicks a link. After clicking we’ll run a little function that changes the URL and updates a content area with new content. Only the new content will be loaded and the URL will be updated. Should the user press the back or forward button, we’ll run the function again and stop the default back/forward behaviour.
Setting it up
We’re going to have two copies of each file. One copy is the ‘quick’ load copy. That’s the one with just the content in it. The second is a copy of the entire page, with everything in it. All the ‘quick’ load copies will be kept in a folder called ‘pages’. The full page copies with everything in it will be in the base directory.
Make sense? So the page-1.html in the pages folder will contain just the content, so it’s just a file full of some paragraphs. The page-1.html in the base directory has the entire page-1.html file. Why? Because we’re going to direct users to a ‘fake’ URL that exists in the base directory. If we didn’t have these full versions of the page then when the user refreshes the page the page would no longer exist and they would get a 404 error. You can always download the files if you feel a bit lost.
I’ve create 3 pages, each with different content. In the index file I’ve included the jQuery file and a Javascript file where I’m going to put all the Javascript. The index.html file is sort of going to act as our base file. When the user clicks another link it is always going to be the index.html file, only the content area will change.
<script src="jquery.js"></script> <script src="javascript.js"></script>
In the body I have the following content:
<div id="container" class="tk-museo-sans"> <div id="header"> <div class="center-player"> <div class="play"> <div class="plbtn"> ► </div> <div class="pabtn"> <span class="bar"> </span> <span class="bar"> </span> </div> </div> <div class="music-author"> Music: <a href="http://freemusicarchive.org/music/Fabrizio_Paterlini/netBloc_Vol_30_aldartea/01_-_Fabrizio_Paterlini_-_Veloma">(Veloma by Fabrizio Paterlini)</a> </div> </div> </div> <div id="content"> <h1>Press The Play Button Above!</h1> <div> Press the play button above and then try clicking <a class="history" href="/demo/history/page-1.html">this link</a>. The music will continue to play but the history and page will, update. <strong>The music will even continue playing if you press the back and forward buttons.</strong> Pretty cool, huh? </div> </div> </div>
And, of course, there is a little CSS to help make things look nicer, which you can see in the download. Lets take a look at the Javascript. We have a simple ‘anchorClick’ function which checks what link the user is clicking and loads the content from our pages directory. It then updates the content div in our HTML with that content.
$(document).ready(function() { function anchorClick(link) { var linkSplit = link.split('/').pop(); $.get('/demo/history/pages/' + linkSplit, function(data) { $('#content').html(data); }); }
Next up we check when the user clicks an anchor, and prevent the default behaviour.
$('#container').on('click', 'a', function(e) { window.history.pushState(null, null, $(this).attr('href')); anchorClick($(this).attr('href')); e.preventDefault(); });
We run the anchorClick function using the href attribute of whatever anchor is being clicked and also run the pushState function. History in a web browser is like a stack. The current page is on top and when you click back one page is removed. Using pushState()
we add another URL to the top of the stack. It has the syntax:
window.history.pushState(state object, title, url);
- state object – This is a JSON object that is passed to the popstate event handler. That’s an event handler that checks when the user presses back or forward
- title – This is used if you want to change the title of this new pseudo page you’re adding to your history stack. It’s currently ignored in most browsers
- url – This is the URL you wish to update to. This is key!
To finish up we have to run the popstate event handler so that we can run the anchorClick function when the user clicks the back or forward button in their browser. This is a pretty useful event handler!
window.addEventListener('popstate', function(e) { anchorClick(location.pathname); });
Finally I have a few other bits and pieces to allow us to play the music track, which is what we’re going to be using to show that only the content is being loaded when using the history buttons in the browser or clicking on links.
var play = false; $('.play').click(function() { if(play == false) { $('#music')[0].play(); play = true; $('.play .plbtn').hide(); $('.play .pabtn').show(); } else { $('#music')[0].pause(); play = false; $('.play .plbtn').show(); $('.play .pabtn').hide(); } }); });
And now we can see it in action. Press play and then click the link in the paragraph and be amazed!
Round up
The history function ties together two key things in web design: efficiency and continuity. It’s a simple function but a powerful tool which will no doubt prove invaluable in the future. Support is mostly fine, with the latest versions of every big browser allowing implementation of this code. Since we have backup files we don’t have to worry about support that much anyway; if the support isn’t there the browser will just navigate to one of our ‘full’ pages in the base directory.
Feature | Chrome | Safari | Firefox | IE | Opera |
History API | 26.0+ | 5.1+ (buggy) | 20.0+ | 10.0+ | 12.1+ |