Thursday, February 13, 2014

How to supercharge your site’s speed with AJAX and jQuery

In this tutorial we’re going to look at how to speed up the user experience on small static sites using a few different methods. (A static site is one which doesn't have any renewing content, so no blog posts or photo streams etc.)
The way we’re going to be doing this is by taking out page reloads. So simply put, when the user uses some navigation links, only the main content of the page changes and it doesn't make the browser reload the page.
We will be achieving this effect in two different ways, the first only uses jQuery, and the other uses AJAX and some PHP. They both have their pros and cons, which we’ll look at as well. Take a look at the demo to see what we’re trying to achieve and let’s start with the first (and simpler) jQuery method.

Achieving the effect with jQuery

First we will look at the setup for the page. The HTML is very simple but has a few important parts, “the essentials” as it were. We need some navigation links which have a specific hash href (which we’ll explain in a minute) and a specified content area which you would already have on any other site anyway. So let’s first see what is in our index.html file:
<body>
<header>
    <h1>Speed Up Static Sites with jQuery</h1>
    <nav>
        <ul>
            <li><a href="#page1" class="active" id="page1-link">Page 1</a></li>
            <li><a href="#page2" id="page2-link">Page 2</a></li>
            <li><a href="#page3" id="page3-link">Page 3</a></li>
            <li><a href="#page4" id="page4-link">Page 4</a></li>
        </ul>
    </nav>
</header>
<div id="main-content">
    <section id="page1">
        <h2>First Page Title</h2>
        <p>First page content.</p>
    </section>
    <section id="page2">
        <h2>Look, no page load!</h2>
        <p>Second page content.</p>
    </section>
    <section id="page3">
        <h2>Ooh fade!</h2>
        <p>Third page content.</p>
    </section>
    <section id="page4">
        <h2>Fourth Page Title</h2>
        <p>Fourth page content.</p>
    </section>
</div> <!-- end #main-content -->
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<script type="text/javascript" src="custom.js"></script>
</body>
So to recap the important parts of what needs to go into the markup: we have our navigation in which each link has an href of the corresponding DIV. So the link to “Page 2″ has a href=”#page2″ (which is the id of the <section> element further down). So with this first method as you can see we have a div of #main-content surrounding our sections, and then each page content one after the other in their own separate ‘section’ element. We also call jQuery and our own custom.js javascript file in which the actual functionality of the site will be made.
But before we get to that we need to add one line to our CSS, there’s no need to go over the whole CSS file for this example as it’s all only for looks, which will change with whatever project you’re working on. However, with this first method there’s one line that’s essential and that’s:
#page2, #page3, #page4 {
display: none;
}
This hides all the ‘pages’ except the first one. So the page appears normally on first load.

The JavaScript

So now to explain what we need to achieve via jQuery. In our custom.js file, we need to target when the user clicks on a navigation link. Retrieve its href link and find the ‘section’ with that same ID, then hide everything in the #main-content div and fade in the new section. This is what it looks like:
$(function() {
    $('header nav a').click(function() {
        var $linkClicked = $(this).attr('href');
        document.location.hash = $linkClicked;
        if (!$(this).hasClass("active")) {
            $("header nav a").removeClass("active");
            $(this).addClass("active");
            $('#main-content section').hide();
            $($linkClicked).fadeIn();
            return false;
        }
        else {
            return false;
        }
    });
    var hash = window.location.hash;
    hash = hash.replace(/^#/, '');
    switch (hash) {
        case 'page2' :
            $("#" + hash + "-link").trigger("click");
            break;
        case 'page3' :
            $("#" + hash + "-link").trigger("click");
            break;
        case 'page4' :
            $("#" + hash + "-link").trigger("click");
            break;
    }
});
This code is split into two sections, the first achieves what we just talked about. It has a click function on the header nav links. It then puts the ‘#page1, #page2′ etc into a variable named $linkClicked. We then update the browser’s URL to have that same hash name. Then we have an if statement making sure the link we’re clicking is not the current tab, if it is then do nothing, but if not hide all current content and unhide the div with an ID of $linkClicked. Simple as that!
The second section checks if the url has a hash link on the end of it, if it does, it finds a corresponding link on the page with the same value (that’s why the links have specific IDs in the markup) and then it triggers that link (it clicks on it). What this does, is means the user can reload a page after having navigated to a ‘page’ and the refresh will send the user back there instead of just back to the first page, which can often be a problem with this sort of system.
So that’s the end of the first method, this results in a working static site that has instantaneous content swapping, and no page reloads. The only drawback to this method is the fact that all the content is called on the initial load, as it’s all there in the index file. This can start to be a problem with photos and extra content making the first site visit load a bit longer. So let’s look at another way to do this same effect which can eliminate that problem.

Using AJAX and PHP

To achieve this same effect but in a slightly different way, so that the initial load isn’t going to load all of our content and thus slow it down (defeating the point if the site has a lot of content) we will use a little PHP and AJAX. This means that the file structure for our project will change and look like this:
So if you look, the index file is now a .php and not a .html. We also have an extra file named ‘load.php’ as well as a new folder/directory called pages in which there are four HTML pages. Now this means that if you’re working locally you need to set up a local development environment using something like MAMP (for Mac) or WAMP Server (for Windows). Or you can upload the whole folder onto a web server if you have access and edit on there, basically you’ll need an environment where the PHP will work.
The index.php has only changed one thing, but it’s important, we will now not load all the content in there, and simply call the initial content in with a PHP include. It now will look something like this:
<body>
<header>
    <h1>AJAX a Static Site</h1>
    <nav>
        <ul>
            <li><a href="#page1" class="active" id="page1-link">Page 1</a></li>
            <li><a href="#page2" id="page2-link">Page 2</a></li>
            <li><a href="#page3" id="page3-link">Page 3</a></li>
            <li><a href="#page4" id="page4-link">Page 4</a></li>
        </ul>
    </nav>
</header>
<div id="main-content">
<?php include('pages/page1.html'); ?>
</div> <!-- end #main-content -->
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<script type="text/javascript" src="custom.js"></script>
</body>
So the line beginning <?php is calling in the first HTML file from our folder of pages and inserting in entirely into our #main-content DIV. The file called can contain whatever content you want to appear on the page.

Using $.ajax in the JavaScript

Let’s move onto the new JavaScript, it now looks slightly different, mainly we’re now using AJAX to fetch the new content from each HTML file when the user clicks on some corresponding navigation. Here’s the first function in the code (the second stays the same as before):
$(function() {
    $('header nav a').click(function() {
        var $linkClicked = $(this).attr('href');
        document.location.hash = $linkClicked;
        var $pageRoot = $linkClicked.replace('#page', '');
        if (!$(this).hasClass("active")) {
            $("header nav a").removeClass("active");
            $(this).addClass("active");
            $.ajax({
                type: "POST",
                url: "load.php",
                data: 'page='+$pageRoot,
                dataType: "html",
                success: function(msg){
                if(parseInt(msg)!=0)
                {
                    $('#main-content').html(msg);
                    $('#main-content section').hide().fadeIn();
                }
            }
        });
    }
    else {
        event.preventDefault();
    }
});
So let’s explain what’s going on. We’re adding one more variable, that’s $pageRoot. This is basically the actual number clicked (taking way the ‘#page’ part of the hash link and leaving the individual number). Then inside the same “if” statement as before we call ajax and use the other PHP file we mentioned earlier to parse the information given (which link has been clicked) and find the corresponding page. Then if it comes back with no error, we insert the new HTML from the file received into our #main-content DIV. Then just to stop it changing suddenly, we hide everything and then fade it in.

load.php

The contents of the new PHP file is short and sweet, it takes the page number that jQuery has sent it and looks to see if the corresponding HTML file exists. If it does it gets all the content and returns it to the AJAX function (which we showed a moment ago that we insert that content into the main DIV).
<?php
if(!$_POST['page']) die("0");
$page = (int)$_POST['page'];
if(file_exists('pages/page'.$page.'.html'))
echo file_get_contents('pages/page'.$page.'.html');
else echo 'There is no such page!';
?>
Following that the site should look however you want it to, but mostly work properly.
That’s it! The site now calls in the right corresponding HTML file each time the user clicks on a navigation link. It swaps out the content without making the page reload. And this way it still doesn’t have to call all the content on the initial page load! I hope you’ve managed to learn some useful method from this tutorial and that you can use it to improve some project in some way.
You can view the jQuery demo here, the PHP demo here, or download the source and take a closer look.