This site is pretty fast, lets be honest static HTML loads incredibly quickly as there is no rendering or database overheads to slow it down. That being said AJAX page loading is even faster so can it be done without the use of HTTP headers etc…?
Yes it can, quite easily, I spent more time working on getting Disqus and Google Analytics working again.
$(document).on('ready', function(){
bindLinks()
})
$(window).on("popstate", function(e) {
// When the browser goes back replace the content and title
$('title').html(e.originalEvent.state.title)
$('#content').html(e.originalEvent.state.content)
})
function bindLinks(){
$("a[href^='/']").on('click', function(e){
// Stop link from activating
e.preventDefault()
// Get the URL to load
url = $(this).attr('href')
// Send a Get request to the URL
$.get(url, function(data){
// Get the title of the new page
regex = /<title>(.*)<\/title>/g
newTitle = regex.exec(data)[1]
// Set the title to the new title
$('title').html(newTitle)
// Replace the content
$('#content').html($(data).find('#content').html())
// Push a new state to the browser
history.pushState({
'title': $('title').html(),
'content': $('#content').html()
}, newTitle, url)
// Re Bind to all the links on the page
bindLinks()
})
})
}
Not much code there is there. So how does it work?
First off in the documents ready event the function bindLinks
gets run which is just to start the process off.
The only part of the function is an event binding for all internal links which in turn starts with a call to e.preventDefault()
to stop the links from being handled by the browser. Next we get the target url from the links href
attribute and send off a get request to it.
The callback for the get request is passed a string containing the HTML for the page which can be passed into jQuery and used like the normal DOM. In Theory… jQuery has some issues around the root node being html/head/body which means you cant just use $(data).find('title')
to get the title of the new page. In light of this I had to use regex to pull the title out of the received code. My content is 2 layers into divs which lets me fetch it quite nicely with $(data).find('#content').html()
making the replace nice and easy.
Then history.pushState
tells the browser the new pages URL and title. Lastly bindLinks
is called again to bind to the links inside #content and that is it!
The code in use on this site is slightly different, I added NProgress to give some feedback to the user that loading is taking place. I also needed to update Google Analytics with the fact that the user has changed page. Lastly Disqus needed to be reset if you opened a second post (which I hope you do).
(document).on('ready', function(){
bindLinks()
})
$(window).on("popstate", function(e) {
NProgress.start()
$('title').html(e.originalEvent.state.title)
$('#content').html(e.originalEvent.state.content)
updateExternals()
bindLinks()
NProgress.done()
})
function bindLinks(){
$("a[href^='/']").on('click', function(e){
// Stop link from activating
e.preventDefault()
// Start the NProgress bar
NProgress.start()
// Get the URL to load
url = $(this).attr('href')
// Send a Get request to the URL
$.get(url, function(data){
// Get the title of the new page
regex = /<title>(.*)<\/title>/g
newTitle = regex.exec(data)[1]
// Set the title to the new title
$('title').html(newTitle)
// Replace the content
$('#content').html($(data).find('#content').html())
// Push a new state to the browser
history.pushState({
'title': $('title').html(),
'content': $('#content').html()
}, newTitle, url)
updateExternals()
// Make NProgress finish
NProgress.done()
// Re Bind to all the links on the page
bindLinks()
})
})
}
function updateExternals(){
// Update Google Analytics
ga('set', 'location', window.location.href);
ga('send', 'pageview');
// Update disqus
// If there is a disqus_thread on the page?
if($('#disqus_thread').length !== 0){
// Has Disqus been loaded before
if ('undefined' !== typeof DISQUS){
// Reset Disqus
DISQUS.reset({
reload: true,
config: function () {
this.page.identifier = disqus_identifier
this.page.url = disqus_url
}
});
}
}
}
This effect is pretty cool and does speed up navigating my site a bit on Github Pages but mostly it just looks cool.
Revised 25/2/16 to include popstate support fixing an issue with going back