Richard York

Web Developer, Author, and Artist

Making a Slideshow with jQuery

Making a Slideshow with jQuery

May 8, 2009 by Richard

Recently, I had the good fortune to see my newest book published, Beginning JavaScript and CSS Development with jQuery. Suffice to say, I've become a pretty big fan of jQuery, and how effortless it makes certain development tasks. If you're not familiar with jQuery, consider having a look at my book, which provides a relatively comprehensive introduction to this ever more ubiquitous JavaScript library.

All obligatory self-promotion aside, I have actually brought you here today for something a little more substantive than book promotion. In this post, I'm going to walk you through how to apply jQuery to an ever more common development scenario, animating a home page slide show.

Typically, you see three panes (or slides) of content. Each slide is displayed briefly followed by an animated transition between one slide and the next. The following screenshot shows an example of a slideshow that I created for a client, The Estridge Companies, at EstridgeExtremeDream.com (sorry, the website is no longer available). I made this website for Estridge, which is a portal showcasing their recent participation in an episode for ABC's Extreme Makeover: Home Edition, which my employer, Westlake Design, donated.

EstridgeExtremeDream.com Screenshot

Usually, you'll find that developers tend to shy away from doing a project like this in JavaScript, and find this kind of thing done in Flash— and before jQuery made JavaScript-driven animations this easy, Flash may honestly have been the best choice for programmers without the time to explore JavaScript animation... but, thankfully, that doesn't have to be the case anymore.

On this particular site, jQuery made quick and easy work of that slideshow, using nothing more than the plain vanilla library that you can download for free from www.jquery.com. In fact, using just the default library you have several options for animating a transition, fade in, fade out, swipe, scale, and even more fine grained control using jQuery's animate() method. In the end, I opted for a fade in/fade out transition, but I could have just as easily used a swipe, or a wide variety of common transition techniques.

Approaching this project is three fold, first you develop the markup structure, then you set in place the CSS to style the document, then you add behaviors using JavaScript and jQuery. In the following source code example, I explain how to create your own slideshow using the same code that I used for Estridge's website, with the relevant slideshow bits isolated.

First, you examine the markup structure.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"></p> <html xmlns='http://www.w3.org/1999/xhtml' xml:lang='en-us'> <head> <meta http-equiv='content-type' content='text/html; charset=utf-8' /> <meta http-equiv='content-language' content='en' /> <title>Slideshow</title> <link rel='stylesheet' type='text/css' href='/Slideshow/Slideshow.css' /> <script type='text/javascript' src='/Library/jQuery/jQuery.js?hFileLastModified=1364984544'></script> <script type='text/javascript' src='/Slideshow/Slideshow.js' charset='utf-8'></script> </head> <body> <div id='tmpSlideshow'> <div id='tmpSlide-1' class='tmpSlide'> <img src='/Slideshow/Slide+1.jpg' alt='Slide' /> <div class='tmpSlideCopy'> <h4>Lorem ipsum dolor</h4> <p> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse leo mauris, sollicitudin vel euismod vitae, sollicitudin sit amet ante. Duis ipsum felis, rutrum eu ultrices sit amet, iaculis a sapien. Ut et leo ut quam tempor auctor. Sed sapien quam, consequat ut adipiscing sit amet, faucibus eget libero. </p> </div> </div> <div id='tmpSlide-2' class='tmpSlide'> <img src='/Slideshow/Slide+2.jpg' alt='Slide' /> <div class='tmpSlideCopy'> <h4>Ut et leo ut quam</h4> <p> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse leo mauris, sollicitudin vel euismod vitae, sollicitudin sit amet ante. Duis ipsum felis, rutrum eu ultrices sit amet, iaculis a sapien. Ut et leo ut quam tempor auctor. Sed sapien quam, consequat ut adipiscing sit amet, faucibus eget libero. </p> </div> </div> <div id='tmpSlide-3' class='tmpSlide'> <img src='/Slideshow/Slide+3.jpg' alt='Slide' /> <div class='tmpSlideCopy'> <h4>Sed sapien quam</h4> <p> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse leo mauris, sollicitudin vel euismod vitae, sollicitudin sit amet ante. Duis ipsum felis, rutrum eu ultrices sit amet, iaculis a sapien. Ut et leo ut quam tempor auctor. Sed sapien quam, consequat ut adipiscing sit amet, faucibus eget libero. </p> </div> </div> <div id='tmpSlideshowControls'> <h4>Features</h4> <div class='tmpSlideshowControl' id='tmpSlideshowControl-1'><span>1</span></div> <div class='tmpSlideshowControl' id='tmpSlideshowControl-2'><span>2</span></div> <div class='tmpSlideshowControl' id='tmpSlideshowControl-3'><span>3</span></div> </div> </div> </body> </html>

The preceding markup should be pretty self-explanatory, you have the document structured so that each slide resides in a container, e.g., the <div> with id name tmpSlideshow. That <div> element will be styled so that it acts as the canvas area for all three slides, it will receive a fixed width and height, and absolutely positioned children elements will be positioned relatively to it.

In order to more easily access each slide from JavaScript, each slide is numbered in its id name. Then the copy is placed in a new <div> container, so that the position of the copy is easier to control.

Finally, at the bottom, you create markup for the buttons that allow control over the slideshow, so that when you press button "1", for example, the slideshow stops, and slide "1" is displayed.

To see how it fits together a little better, let's apply a little CSS.

body { font-family: Arial, sans-serif; } div#tmpSlideshow { margin: 10px; padding: 30px 0 0 0; position: relative; height: 335px; width: 755px; border: 1px solid rgb(200, 200, 200); } div.tmpSlide { position: absolute; top: 0; left: 0; width: 730px; height: 332px; display: none; } div.tmpSlide img { float: left; margin: 30px 0 0 15px; width: 527px; border: 1px solid rgb(244, 244, 244); } div#tmpSlideshowControls { position: absolute; bottom: 30px; right: 11px; width: 175px; } div.tmpSlideshowControl { border: 1px solid #e1dece; float: left; margin: 0 5px 0 0; background: url('/Template/Pictures/Buttons/Feature.png') no-repeat; width: 38px; height: 36px; color: #554d31; font: 14px Arial, sans-serif; text-align: center; cursor: pointer; } div.tmpSlideshowControl span { line-height: 36px; vertical-align: middle; } div.tmpSlideshowControlOn { background-image: url('/Template/Pictures/Buttons/FeatureOver.png'); } div.tmpSlideshowControlActive { border: 1px solid rgb(161, 155, 137); } div.tmpSlideCopy { position: absolute; left: 565px; top: 20px; width: 170px; } div#tmpSlideshow h4 { color: #b90f23; text-transform: uppercase; font: 14px Arial, sans-serif; margin: 10px 0; } div.tmpSlideCopy p { font: 11px Arial, sans-serif; line-height: 1.75em; }

In the preceding CSS, each slide is positioned absolutely, relative to the <div> with id name tmpSlideshow, just as I promised they would be. Then, within each slide, each image is floated left, and the copy is positioned absolutely to the right side. The controls are positioned to the bottom of the container. All-in-all a very painless and straight-forward stylesheet.

To get ready for jQuery, you add a few styles that will be applied dynamically. A style for when the controls are moused over by the user, and a style to indicate which slide is active, by drawing a dark border around the control that goes with the currently active slide.

The rule with the selector div.tmpSlideshowControlOn is applied when the user mouses over a slideshow control. And the rule with the selector div.tmpSlideshowControlActive is applied to indicate which slide the user is currently seeing by drawing that dark border around the relevant control.

Now that you have markup and CSS, the final step is to apply JavaScript and jQuery, the following code makes the slideshow function.

var $$ = $.fn; $$.extend({ SplitID : function() { return this.attr('id').split('-').pop(); }, Slideshow : { Ready : function() { $('div.tmpSlideshowControl') .hover( function() { $(this).addClass('tmpSlideshowControlOn'); }, function() { $(this).removeClass('tmpSlideshowControlOn'); } ) .click( function() { $$.Slideshow.Interrupted = true; $('div.tmpSlide').hide(); $('div.tmpSlideshowControl').removeClass('tmpSlideshowControlActive'); $('div#tmpSlide-' + $(this).SplitID()).show() $(this).addClass('tmpSlideshowControlActive'); } ); this.Counter = 1; this.Interrupted = false; this.Transition(); }, Transition : function() { if (this.Interrupted) { return; } this.Last = this.Counter - 1; if (this.Last < 1) { this.Last = 3; } $('div#tmpSlide-' + this.Last).fadeOut( 'slow', function() { $('div#tmpSlideshowControl-' + $$.Slideshow.Last).removeClass('tmpSlideshowControlActive'); $('div#tmpSlideshowControl-' + $$.Slideshow.Counter).addClass('tmpSlideshowControlActive'); $('div#tmpSlide-' + $$.Slideshow.Counter).fadeIn('slow'); $$.Slideshow.Counter++; if ($$.Slideshow.Counter > 3) { $$.Slideshow.Counter = 1; } setTimeout('$$.Slideshow.Transition();', 5000); } ); } } }); $(document).ready( function() { $$.Slideshow.Ready(); } );

The JavaScript is written as a jQuery plugin, actually two plugins. SplitID() and Slideshow.

SplitID() is very simple, you call it on a DOM markup element, it takes that element's id name, splits it on the hyphen and returns whatever characters appear after the last hyphen.

SplitID : function() { return this.attr('id').split('-').pop(); }

For example, if you have the id name tmpSlide-3, SplitID() returns "3".

The second plugin, Slideshow is an object, with sub functions, this object contains all the functionality associated with the slideshow itself.

The first method that you see inside of the Slideshow object is the Ready() method.

Ready : function() { $('div.tmpSlideshowControl') .hover( function() { $(this).addClass('tmpSlideshowControlOn'); }, function() { $(this).removeClass('tmpSlideshowControlOn'); } ) .click( function() { $$.Slideshow.Interrupted = true; $('div.tmpSlide').hide(); $('div.tmpSlideshowControl').removeClass('tmpSlideshowControlActive'); $('div#tmpSlide-' + $(this).SplitID()).show() $(this).addClass('tmpSlideshowControlActive'); $$.Slideshow.Counter = parseInt($(this).SplitID()); setTimeout('$$.Slideshow.Resume();', 5000); // Resume after 5 seconds } ); this.Counter = 1; this.Interupted = false; this.Transition(); }

The Ready() method sets everything up for you, and it's called once the DOM has finished loading, via jQuery's ready() event.

$(document).ready( function() { $$.Slideshow.Ready(); } );

Going back to $$.Slideshow.Ready(), the function attaches events to the slideshow controls, using a jQuery selector, $('div.tmpSlideshowControl'), which applies jQuery hover() and click() events to each <div> with class name tmpSlideshowControl. The hover() event just adds the class name tmpSlideshowControlOn to each of those <div> elements when the user mouses over a control, and removes that class name when the user's mouse leaves a control. The first callback function in the hover() event is executed at the JavaScript onmouseover event, and the second callback function is executed at the JavaScript onmouseout event.

.hover( function() { $(this).addClass('tmpSlideshowControlOn'); }, function() { $(this).removeClass('tmpSlideshowControlOn'); } )

One of the great things about jQuery is the ability to chain multiple method calls to a selection. In this example, after you've applied jQuery's hover() event, you can continue adding more events or performing operations on the selection by chaining calls to other jQuery methods. In this case, you chain a call to jQuery's click() method, which adds a JavaScript onclick event to each <div> element with class name tmpSlideshowControl.

.click( function() { $$.Slideshow.Interupted = true; $('div.tmpSlide').hide(); $('div.tmpSlideshowControl').removeClass('tmpSlideshowControlActive'); $('div#tmpSlide-' + $(this).SplitID()).show() $(this).addClass('tmpSlideshowControlActive'); $$.Slideshow.Counter = parseInt($(this).SplitID()); setTimeout('$$.Slideshow.Resume();', 5000); // Resume after 5 seconds } );

In the preceding call to jQuery's click() method, you attach a callback function that executes whenever a user clicks on one of the <div> elements acting as a slideshow control. Inside of that callback function, you flag that slideshow as interrupted by setting the variable $$.Slideshow.Interrupted to true. Setting this variable to true is used later in the program to stop the automated slide transition. Next all slides are hidden using $('div.tmpSlide').hide();. And the class name tmpSlideshowControlActive is removed from all slide controls. This gives you a blank slate to work with, at this point, no slides are displayed, and no slides are set active. Next you display the slide corresponding to the control the user clicked on with this code: $('div#tmpSlide-' + $(this).SplitID()).show(). Using this code, you select the slide by calling its id name. SplitID() gets the right slide, so if you click on the control with id name tmpSlideshowControl-1, the slide with id name tmpSlide-1 is displayed. Then, finally, the control corresponding to the slide being displayed is given the class name tmpSlideshowControlActive, giving the user a visual indication of which slide they are currently viewing.

The remainder of the $$.Slideshow.Ready() function sets up your slide show.

this.Counter = 1; this.Interrupted = false; this.Transition();

The Counter variable sets which slide will be displayed first, and subsequently is used to keep track of which slide the user is currently seeing. Then again, the Interrupted variable is used to stop the slide show if the user clicks on a control. Finally, the automated transition is started with a call to this.Transition();

The body of the Transition() function is displayed below:

Transition : function() { if (this.Interrupted) { return; } this.Last = this.Counter - 1; if (this.Last < 1) { this.Last = 3; } $('div#tmpSlide-' + this.Last).fadeOut( 'slow', function() { $('div#tmpSlideshowControl-' + $$.Slideshow.Last).removeClass('tmpSlideshowControlActive'); $('div#tmpSlideshowControl-' + $$.Slideshow.Counter).addClass('tmpSlideshowControlActive'); $('div#tmpSlide-' + $$.Slideshow.Counter).fadeIn('slow'); $$.Slideshow.Counter++; if ($$.Slideshow.Counter > 3) { $$.Slideshow.Counter = 1; } setTimeout('$$.Slideshow.Transition();', 5000); } ); }

The function begins by checking the value of the Interrupted variable, if it is true, the function returns, which effectively stops the automated transition between slides, so that when a user clicks on a button, they see only that slide.

if (this.Interrupted) { return; }

Next, you need to determine what slide was the last slide to be displayed, to do this, you subtract "1" from the variable Counter, which is used to keep track of which slide is currently on display. If the value of Last is less than "1", then the value is reset to "3", which ensures that the value of Last is always "1", "2", or "3", corresponding to a numbered slide.

Next, you transition the slide currently on display using jQuery's fadeOut() method.

$('div#tmpSlide-' + this.Last).fadeOut( 'slow', function() { } );

You use the variable Last to select the right slide by its id name, then jQuery's fadeOut() method does all the work. Passing the argument "slow" causes jQuery's fadeOut() to use a defined length of time, which may or may not line up with your idea of "slow", if not, you can also specify the amount of time you want the transition to take in milliseconds. Then, of course, the fadeOut() method animates the element's opacity, providing a smooth transition between fully opaque and fully transparent.

The 2nd argument passed to jQuery's fadeOut() method is a callback function that is executed once the animation of the element's opacity completes.

After the element has been hidden, you remove the class tmpSlideshowControlActive from the corresponding control, and add the same class to the next slide, then fade in the new slide. Then finally, the counter is incremented. If the counter is greater than "3", the counter is reset to "1".

The last order of business is to call JavaScript's setTimeout() method. The first argument provides a call to the Transition() method in a string, the second argument provides the amount of time in milliseconds to wait before calling the method again. 5000, corresponds to "5" seconds.

function() { $('div#tmpSlideshowControl-' + $$.Slideshow.Last).removeClass('tmpSlideshowControlActive'); $('div#tmpSlideshowControl-' + $$.Slideshow.Counter).addClass('tmpSlideshowControlActive'); $('div#tmpSlide-' + $$.Slideshow.Counter).fadeIn('slow'); $$.Slideshow.Counter++; if ($$.Slideshow.Counter > 3) { $$.Slideshow.Counter = 1; } setTimeout('$$.Slideshow.Transition();', 5000); }

Take a look at the completed slideshow demo.

Comments

  • August 6, 2009 Sven says:

    Very nice explanation and well working script.. but how do i modify the script that it gets the maximum amount of slides automatic? If i generate the slide dynamic within a cms for example no one can say what the maximum number of slides will be.. so you have to update the *.js everytime by hand at this parts :/ # if (this.Last < 1) { # this.Last = 3; # } # if ($$.Slideshow.Counter > 3) { # $$.Slideshow.Counter = 1; # } Would be nice if you could help me (and i think many others) at this point :)
  • August 6, 2009 Richard York says:

    Are you asking, how do you make it so that you can have a variable number of slides? Should be easy enough, you just replace references to "3" in the JavaScript with something like $('div.tmpSlide').length, then you can have as many slides as you like.
  • August 11, 2009 Sven says:

    Exactly what i searched for. Will test it as soon as i have the time.. but i think thats the right start :) Thank You very much
  • August 26, 2009 Tim says:

    Very nice, compact plugin! I would suggest two things to make it really cool: 1. Fade to the target slide when a control is clicked instead of the abrupt change that happens now. and 2. Resume the cycle after a certain number of seconds after clicking a control.
  • September 10, 2009 Daniel says:

    Exactly what i need. But I'm having problems on how to use the jquery and java scripts. I put everything on the same file and put the jquery inside java tags, css inside css tags and the html in html tags but the pictures are not showing let alone the transition. Thanks
  • October 2, 2009 Marco says:

    Is possibile to create a cross fade effect between 2 images ? Ad not that image fade out to white as do now the script ?
  • October 10, 2009 Rick says:

    Thanks for the clean script and great explanation.
  • November 10, 2009 tina says:

    How do I resume the cycle after a certain number of seconds after clicking a control. Any inputs would be appreciated ..
  • November 11, 2009 Chris Porter says:

    I'm having the same problem tina is having. Is there a way to resume the cycle from where the user clicked and viewed the slide for a moment?
  • November 11, 2009 Richard York says:

    With regards to resuming the slideshow... Once you click on one of the controls the slideshow is totally paused and will remain paused until you tell it to start again. One way of starting it again is to set a timeout in the click() event to call another function that resets the Interrupted variable to "false", and resumes the slideshow by calling the "Transition()" method. I've amended the code to reflect that approach. With regards to cross-fade, etc, insert your effect of choice here... Cross-fading would require that you start the fadeIn() of the subsequent slide at the same time you do the fadeOut() of the current slide. Therefore, you would need to move the logic that fades in the subsequent slide from inside of the callback function executed once fadeOut() is completed to occur just after the call to fadeOut(), so both fade in and fade out are occurring at the same time. Other effects can be used, jQuery has a nice easing library and a few other built-in animated effects.

There are no comments posted at this time.

Leave a Comment

Simple HTML is allowed: <code>, <b>, <i>, <u>, <var>, <strong>, <em>, <blockquote>, <ul>, <ol>, <li>, <p> (no attributes). All spacing and line breaks in your comment will be preserved.

* All comments are moderated and are subject to approval.
Your comment will appear once it has been approved.
Posting multiple times will not expedite the approval process.

Archive

© Copyright 2014 Hot Toddy, All Rights Reserved.