It’s impossible to deny the effect that jQuery has had on the web since its inception in 2006. Today, developers can use one convenient API and actually concentrate on getting things done when it comes to their complex web applications. While cross browser issues still exist (I’m looking at you Internet Explorer), jQuery has helped reduce the issues significantly. With all this spare time to focus on the UI instead of implementation details, web applications are getting brand new life with features that really “Wow!” the end user.

One constant seems to remain in the ever growing world of great UI features: the slideshow. Whether it’s showing off information, swapping images or the like, a slideshow is a great interactive piece for end users to engage with. While there are a plethora of jQuery plugins that can do this for you, this article is going to dig into the nuts and bolts behind building your own jQuery slideshow from scratch.

I know what you might be thinking, and I wouldn’t blame you: “Man, building a jQuery slideshow from scratch is hard!” I was of the same mindset when I first wanted to dig deep into building a great slideshow. What I found is that if you understand a few crucial JavaScript principles the end product is not so complicated to grasp. We can combine the convenient API that jQuery gives us with some vanilla JavaScript to create some really neat stuff.

Now, before I start every project the first thing I like to do is think about the steps. I like to visualize exactly what the code needs to do, how it needs to do it and what features it would have to use in order to make it work properly. In the case of a slideshow, let’s think about 5 images that you might want to be able to swap through easily and quickly. I decided to use images of puppies because honestly who doesn’t love puppies?

After pondering briefly about what steps would be required of a slideshow, I came up with the following:

  • For every slide that exists for the slideshow, starting from the first one, stack them on top of each other. This can be done easily with the z-index attribute.
  • The slideshow will have to run on some sort of interval to change. We could use the JavaScript setInterval function to run code every so often.
  • Since the slides are stacked on top of each other, when one fades out it will reveal the one underneath it. This can be done using jQuery’s fadeOut method.
  • When the next to last slide fades out (slide number 4) and reveals the last slide underneath it’s time for the process to start over.
  • Fade in the first slide and then show the other slides underneath it to bring back their opacity since they have been faded out. This could be done using jQuery’s fadeIn method and passing it a callback to wait until the slide has officially faded in before showing the others underneath. The user won’t see the slides underneath showing, but it’s important for when the process officially starts over again.


Keep in mind that the above points ensure that we can add as many slides as we want to our slideshow and the code will do the work. We want to write our code to be as dynamic as possible so we won’t have a lot to maintain.

With a blueprint in hand, let’s start building. If you want to download the final product you can do so here. This is simply a stripped down version of the HTML5 boilerplate where all of the final JavaScript can be found in the main.js file in the js directory. To see a functional version of the slideshow we will build, follow this link.

You will find that while the HTML and CSS are extremely straight forward, the JavaScript may not be. Don’t worry, we will be dissecting that piece by piece in just a moment.

HTML

<div id="slideshow">
    <img class="slide" src="img/puppy1.jpg" />
    <img class="slide" src="img/puppy2.jpg" />
    <img class="slide" src="img/puppy3.jpg" />
    <img class="slide" src="img/puppy4.jpg" />
    <img class="slide" src="img/puppy5.jpg" />
</div>

As I said, extremely straight forward HTML. This is just a div with an id of slideshow with some child nodes that each have the class of slide. This could also work with divs, sections or anything really. This slideshow isn’t limited to just images.

CSS:

#slideshow {
    width: 500px;
    height: 500px;
    margin: 0 auto;
    position: relative;
}
.slide {
    width: 500px;
    height: 500px;
    position: absolute;
    left: 0;
    top: 0;
}

The #slideshow selector has a width and height of 500 pixels with the margin: 0 auto; trick to center the slideshow in the browser. We will use position: relative on the #slideshow element so we can position the child nodes inside of it with position: absolute.

You will see that elements with the slide class are given the same width and height as the element with the id of slideshow and use the left: 0; and top: 0; so they are aligned properly.

JavaScript:

/*global $,jQuery,console,window*/
(function ($) {
    "use strict";
    var slideshow = (function () {
        var counter = 0,
            i,
            j,
            slides =  $("#slideshow .slide"),
            slidesLen = slides.length - 1;
        for (i = 0, j = 9999; i < slides.length; i += 1, j -= 1) {
            $(slides[i]).css("z-index", j);
        }
        return {
            startSlideshow: function () {
                window.setInterval(function () {
                    if (counter === 0) {
                        slides.eq(counter).fadeOut();
                        counter += 1;
                    } else if (counter === slidesLen) {
                        counter = 0;
                        slides.eq(counter).fadeIn(function () {
                            slides.fadeIn();
                        });
                    } else {
                        slides.eq(counter).fadeOut();
                        counter += 1;
                    }
                }, 2000);
            }
        };
    }());
    slideshow.startSlideshow();
}(jQuery));

Here is the final JavaScript that makes your slideshow run. As I mentioned earlier, if we understand a few key JavaScript principles, this is a walk in the park.

The first thing you may notice about the JavaScript is that it’s wrapped in an immediately invoked function expression, like so:

(function ($) {
    "use strict"
    //code here
}(jQuery));

Since JavaScript has one global object (window), any variables you write in a global scope actually become properties of the window object. This is considered bad practice because you could be overwriting globals that already exist. Instead of cluttering up the global scope we can create our own scope with an immediately invoked function expression to encapsulate our code. You will also notice we’re passing the $ to the jQuery object so there is no confusion about what the $ does in this scope.

We will also write "use strict" to enable JavaScript strict mode. While strict mode is outside the realm of this article, you can find more information on it here.

var slideshow = (function () {
    var counter = 0,
        i,
        j,
        slides =  $("#slideshow .slide"),
        slidesLen = slides.length - 1;
    for (i = 0, j = 9999; i < slides.length; i += 1, j -= 1) {
        $(slides[i]).css("z-index", j);
    }
}());

Here we define a variable called slideshow. The value of the slideshow variable is another immediately invoked function expression which is run on script execution. Inside of this is where we set up our environment variables for the slideshow and declare some variables for later use.

var slideshow = (function () {
    //code
}());

You will notice that all of the variables that we will use for our slideshow are all separated by a comma to make it more concise.

var counter = 0,
    i,
    j,
    slides =  $("#slideshow .slide"),
    slidesLen = slides.length - 1;

The first variable, counter, is going to act as the heart of the slideshow. The counter variable will change intermittently and as it does so will our slideshow.

var counter = 0,

The variables i and j are just being declared for later use.

i,
    j,

The slides variable is a jQuery object that contains all of our slide nodes.

slides =  $("#slideshow .slide"),

While the slidesLen variable contains an integer of how many slides there actually are minus 1. This might not make a lot of sense right now, but it will.

slidesLen = slides.length - 1;

The last bit of code is actually a for loop which handles the stacking of our slides on top of each other. The variable i starts at 0 and j starts at 9999 and will be used for our z-index value. You could change j to be anything you want to better work with your web application. When the for loop runs it tests to see if i is less than slides.length. If true, increase i and decrease j on the next pass. In the body of the for loop it finds the i (current value of i) slide in the jQuery object and assigns it’s z-index value to whatever j is equal to. The for loop will decrease the z-index gradually for each slide until we get all of the slides stacked on top of each other. This is exactly what we wanted.

for (i = 0, j = 9999; i < slides.length; i += 1, j -= 1) {
        $(slides[i]).css("z-index", j);
    }

The Almighty Closure

At this point in the code we have been successful in setting up everything that we may need for our slideshow. While all of the variables declared are important, it’s really the counter variable that is at the center of the functionality. Without counter the slideshow would not run properly. It may go without saying that we don’t want just anyone to be able to change that value. What we need is to be able to retrieve and update counter if we need to, but privately. This sounds like a perfect case for a closure.

You see, the value of slideshow is itself an immediately invoked function expression so it runs as soon as the script is executed. It sets up all of the variables and runs the for loop. When the slideshow function returns, it returns an object with one method called startSlideshow, thus creating a closure.

return {
    startSlideshow: function () {
        window.setInterval(function () {
            if (counter === 0) {
                slides.eq(counter).fadeOut();
                counter += 1;
            } else if (counter === slidesLen) {
                counter = 0;
                slides.eq(counter).fadeIn(function () {
                    slides.fadeIn();
                });
            } else {
                slides.eq(counter).fadeOut();
                counter += 1;
            }
        }, 2000);
    }
};

In this instance, the startSlideshow method is able to retrieve and update any variables declared when slideshow was run. There is no way to actually change any variables from outside slideshow (unless you’ve created a setter method) so this variable is only seen by the startSlideshow method being returned in the object.

With that out of the way, let’s dig deeper into the guts of the startSlideshow method.

We have a setInterval method that takes two parameters.

window.setInterval(function () {
    //code      
}, 2000);

The first parameter passed is the function we want to run and the second is an integer which determines how often to run the function you’ve passed. In this case, the function passed will run every 2000 milliseconds.

Inside of the setInterval method we have a sizable conditional statement.

if (counter === 0) {
    slides.eq(counter).fadeOut();
    counter += 1;
} else if (counter === slidesLen) {
    counter = 0;
    slides.eq(counter).fadeIn(function () {
        slides.fadeIn();
    });
} else {
    slides.eq(counter).fadeOut();
    counter += 1;
}

The first condition tests to see if the counter variable that we declared and initialized earlier is equal to 0. On the first pass through, this will be true. The slides.eq(counter).fadeOut(); finds the first slide node in the jQuery object and fades it out. We increase counter by 1 so on the next pass it can deal with the next slide in the jQuery object.

if (counter === 0) {
    slides.eq(counter).fadeOut();
    counter += 1;
}

The second condition tests to see if counter is equal to the slidesLen variable. Remember, the slidesLen value is an integer that is 1 less than the total amount of slides. So, if the condition equals true, then we know that the very last slide is being shown and it’s time to start the slideshow over.

} else if (counter === slidesLen) {
    counter = 0;
    slides.eq(counter).fadeIn(function () {
        slides.fadeIn();
    });
}

The first thing we want to do here is set counter to 0 so it knows to deal with the first slide and not the last. We fade in the first slide and pass the fadeIn(); method a callback (we want the code to wait until the first slide is done fading in). When the first slide has faded in all the way we can show all of the other slides underneath it so they can be faded out again.

The last part of the conditional only runs if every other test fails.

} else {
    slides.eq(counter).fadeOut();
    counter += 1;
}

This must mean that we’re dealing with a slide that is not the first nor the last but in between.

All that’s left to do is to call the object method. Since slideshow has already returned an object with a method in it all that’s left to do is run it.

slideshow.startSlideshow();

While the slideshow may just run right now this shouldn’t limit you from adding your own methods to the object returned by slideshow.

In conclusion, you can see how understanding scoping and the power of closures can help you create awesome features with not a lot of effort. With very minimal code we managed to make a slideshow that is contained and doesn’t introduce anything new into the window object.

What’s next?