A Simple jQuery Slideshow

In the interest of following jQuery’s motto of “writing less and doing more,” let’s write a simple slideshow using jQuery, JavaScript and a bit of CSS.

Simple jquery slideshow.

For starters, our main goal should be keeping the markup as clean as possible:


<div id="slideshow">
    <img src="img/img1.jpg" alt="" class="active" />
    <img src="img/img2.jpg" alt="" />
    <img src="img/img3.jpg" alt="" />
</div>

Now let’s use CSS to position the images on top of each other and bring the active image to the top level with z-index:


#slideshow {
    position:relative;
    height:350px;
}

#slideshow IMG {
    position:absolute;
    top:0;
    left:0;
    z-index:8;
}

#slideshow IMG.active {
    z-index:10;
}

#slideshow IMG.last-active {
    z-index:9;
}

Due to absolute positioning, we need to define the height of the slideshow DIV. Also, notice that we defined three different z-indexes—we will manipulate these soon using jQuery.

For the slideshow animation we are going to switch between each photo at a set rate. So let’s start by writing a function that brings in a new photo on top of the last active image:


function slideSwitch() {
    var $active = $('#slideshow IMG.active');
    var $next = $active.next();    

    $next.addClass('active');

    $active.removeClass('active');
}

$(function() {
    setInterval( "slideSwitch()", 5000 );
});

Here we set a JavaScript interval to call slideSwitch() every 5 seconds. Then slideSwitch() applies the CSS class ‘active’ to bring the next image to the top of the stack. Since we will select the images more than once within slideSwitch(), we define the variables $active and $next for selector performance.

Next we should incorporate a fade animation. For a gallery like this, fade in and fade out are identical, but let’s not forget to think about what we fade against:


function slideSwitch() {
    var $active = $('#slideshow IMG.active');
    var $next = $active.next();

    $active.addClass('last-active');

    $next.css({opacity: 0.0})
        .addClass('active')
        .animate({opacity: 1.0}, 1000, function() {
            $active.removeClass('active last-active');
        });
}

$(function() {
    setInterval( "slideSwitch()", 5000 );
});

We start by applying the ‘last-active’ class we defined earlier. Since ‘.last-active’ falls after ‘.active’ in the stylesheet, the z-index of 9 takes priority, and the top image drops back a level. Next, we set the opacity of the new image to 0 so that we can fade it in using the animate() function. Finally, we attach a callback to remove the z-index classes from the previous image when animate() completes.

Although our slideshow is working well, we should make it more robust by building in some default variables. First, let’s define a default active image, in case we need to put less stress on the back-end. Also, we can use defaults to make the gallery animation loop.


function slideSwitch() {
    var $active = $('#slideshow IMG.active');

    if ( $active.length == 0 ) $active = $('#slideshow IMG:last');

    var $next =  $active.next().length ? $active.next()
        : $('#slideshow IMG:first');

    $active.addClass('last-active');

    $next.css({opacity: 0.0})
        .addClass('active')
        .animate({opacity: 1.0}, 1000, function() {
            $active.removeClass('active last-active');
        });
}

$(function() {
    setInterval( "slideSwitch()", 5000 );
});

We first define a default image for the $active variable, which interestingly enough needs to be the last image on the stack. This is because through absolute positioning, the last image appears on top, and we need to start with it if we want to avoid any flicker.

For the loop it is pretty simple: all we have to do is point the $next variable to the first image once it has gotten to the end of the line.

If you want to improve this function, try setting the animation speed with a variable so the main slideshow function can be thrown into the core and left alone. Also, this slideshow is easily converted to support DIV’s instead of IMG’s—try programming a slideshow with more content.

Now for a challenge: the gallery flickers when the images first load, but it can be fixed without touching the JS or markup at all. Bonus points to whoever figures it out and posts a comment.

Pimp My Blog:
  • StumbleUpon
  • Digg
  • Reddit
  • del.icio.us
  • Facebook

Posted on Tuesday, July 29th, 2008 at 10:14 am in webdev.

Tags: , , , , ,
RSS 2.0 | Trackback |

45 Responses to “A Simple jQuery Slideshow”

  1. edu Says:

    So far, (so simple) so good. Thanks for sharing this. It just work like a charm, so smoothly. I´ve been trying different jquery slideshows for days but they were too complex and bulky or hard to implement for non developpers like me and all I needed was this, a few images with a smooth fade transition.

    Nice blog. Keep it up!

  2. JeremyB Says:

    Thank you for this! It works wonderfully with just images. However, I’d like each image to be a hyperlink, and when I wrap it in the appropriate tags, the fade does not work properly. Any advice?

  3. Jon Raasch Says:

    Replace every “IMG” with “A” in the Javascript and CSS. If you are using the “active” class, attach it to the anchor (A) tag instead of the image.

    A more robust solution is to wrap each frame in a div and target the div’s instead of the images (or anchors). This would allow you to add text, multiple images, etc.

  4. JeremyB Says:

    To answer my question, it was because the css and js files referenced switching images, not divs. Wrapping the hyperlinked images in divs and changing the references in the css and js files fixed it all. I’m a javascript n00b so sorry if this is totally obvious. Thanks again!

  5. JeremyB Says:

    OK, new problem: A js-based dropdown menu disappears behind my slideshow. I’m thinking this is a z-index problem but nothing seems to work. See it in action at http://www.arenaracinggr.com

  6. JeremyB Says:

    Annnd it was a z-index problem. Sorry to keep spamming up this board. Feel free to delete my comments, and thanks again for the excellent work.

  7. tudor Says:

    to show 1st pic and avoid flickering I did:

    $(document).ready(function(){
    $(’#slideshow IMG’).css({opacity: 0.0});
    $(’#slideshow IMG:first’).css({opacity: 1.0});
    setInterval( “slideSwitch()”, 2000 );
    });

    and set the 1st picture to class=”active”. maybe it’s not the best way

  8. Geoff Cheshire Says:

    Looks something with those first and last PNGs does it? Are you preloading that? Hmm, this is a pretty good puzzle. Any hints?

  9. Jon Raasch Says:

    OK here’s a hint: Tudor was on the right track with attacking the opacity value, since we target this attribute with our jQuery fade function. You could use his solution—it isn’t very resource intensive because it only loads once.

    However, these days it’s important to use as little JavaScript as possible. Try adjusting the CSS directly, instead of modifying it thru the DOM with jQuery.

    Thanks for reading and good luck!

  10. Geoff Cheshire Says:

    Start images with opacity:0.0; via CSS in the #slidehow block?

  11. Geoff Cheshire Says:

    Except for the IMG.active image, that is.

  12. Jon Raasch Says:

    Great work Geoff, that’s the winner!

    By handling the opacity values with the stylesheet and not the JS, you make sure that you are both conserving resources and loading the images with these styles already attached. When coding a JavaScript heavy front end, I like to think of the stylesheets as sort of a base state, which I later manipulate thru scripting.

    If you’re a cut-and-paster here’s that portion of the CSS:

    
    #slideshow IMG {
        position:absolute;
        top:0;
        left:0;
        z-index:8;
        opacity:0.0;
    }
    
    #slideshow IMG.active {
        z-index:10;
        opacity:1.0;
    }
    
  13. Pietro Says:

    Great script but have one issue — I’m using a DIV instead of IMG and everything plays fine but the first div seems to want to wait a couple second before loading. Once it loads all’s well and the script loops perfectly. Not sure what the resolution might be but would take any and all hints. THANKS!

  14. Geoff Cheshire Says:

    Yay! Makes total sense once you think about it (as most puzzles do). Thanks for the nifty script!

  15. United Voices Says:

    Cool.. thanks for this blog mate.

  16. chris Says:

    this is great, it works perfect!

    one problem is when you switch between tabs in FF, it changes images but without the fade.

    is that a problem or just me?

  17. Jon Raasch Says:

    Hey Chris,

    This slideshow works in all major browsers so the problem must be on your side.

    One of my favorite parts about jQuery is that it has been thoroughly engineered to work in every browser you’d want. It takes a lot of the guesswork and hacking out of Javascript, so you shouldn’t worry about JS problems. Look instead to your stylesheets—I’d guess you have a z-index overwriting the one we set in the slideshow CSS.

    Good luck!

  18. chris Says:

    Alright thanks for the quick reply.

    I am going to implement it in some websites now :D

    thanks again for this!!!

  19. Benek Says:

    This is brilliant. Worked perfectly for me.

    As a front-end designer who’s just getting into jQuery I found using this a great learning experience, and it’s so much better and more lightweight that using a big slideshow plugin that’s way more than I need.

    Thanks for sharing!

  20. barney Says:

    This is sweet, I just have one question? Do the images have to be the same size because if they are not they show up behind the active one. Can the images not be preloaded to avoid this?

  21. Helmut Says:

    Hey!
    Thanks for your script. I added some lines to enhance the behaviour - I wanted the images to be centered and don’t overlap each other (occurs if some have smaller width than others)
    (My slideshow uses divisions - inside them are image-elements; the size of the slideshow is fixed)

    #slideshow {
    position: relative;
    width: 450px !important; /*set your width*/
    height: 299px !important; /*set your height*/
    margin-right: 20px;
    margin-left: 20px;
    background-color: #000000; /*i needed a black background*/
    }
    #slideshow div {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    z-index: 100;
    opacity: 0.0;
    text-align: center;
    }
    #slideshow div.active {
    z-index: 102;
    opacity: 1.0;
    }
    #slideshow div.last-active {
    z-index: 101;
    }

    function slideSwitch() {
    var $active = $(’#slideshow div.active’);
    if ( $active.length == 0 )
    $active = $(’#slideshow div:last’);
    var $next = $active.next().length ? $active.next()
    : $(’#slideshow div:first’);
    $active.addClass(’last-active’)
    .animate({opacity : 0.0}, 1000);
    $next.css({opacity: 0.0})
    .addClass(’active’)
    .animate({opacity: 1.0}, 1000, function() {
    $active.removeClass(’active last-active’);
    });
    }

    I added an animation to crossfade the last-active and active element.

    Thought I just comment this, if somebody wants crossfading images with a certain background.

  22. Helmut Says:

    forgot something: the last-active class, their assignments and deletion can be deleted ;)

    and to avoid overlays in IE add
    “filter: alpha(opacity=0);” in #slideshow div and
    “filter: alpha(opacity=100);” in #slideshow div.active
    to your css

  23. Tim Parkes Says:

    you are a lifesaver, i’ve been messing with complicated slideshows for ages trying to get them to work, this is perfect and only took half an hour to implement!

    thank you!

  24. William B Says:

    Thanks to Jon and Helmut… This is great. I was playing around with this and tried putting the slideshow div inside of a table. After that the fade effect stopped working in IE even though it still works in FF. The pics still rotate just no fade in fade out. Any ideas on how to make it work nested inside a table in IE?

  25. Nick Says:

    Hi,

    Thanks for this slideshow, its almost what was I’ve been looking for.

    However, I’m after a way of pausing the slideshow when you over the mouse over.

    Adding one line in this -

    $next.css({opacity: 0.0})
    .addClass(’active’)
    .animate({opacity: 1.0}, 1000, function() {
    $active.removeClass(’active last-active’);
    $(’a').hover(’pause’); //extra line here is here!
    });
    }

    Causes the images to pause, but the links still cycle through as normal.

    My jquery/javascript knowledge is limited, so wondering if you know of a solution to this?

    :)

  26. Jon Raasch Says:

    Hi Nick,

    First when you set the interval, you want to assign it a variable:

    
    var playSlideshow =  setInterval( "slideSwitch()", 5000 );
    

    Next use the jQuery hover method:

    
    $(’#slideshow').hover(function() {
        clearInterval(playSlideshow);
    },
    function() {
        playSlideshow =  setInterval( "slideSwitch()", 5000 );
    });
    

    The jQuery hover method can be used to assign two functions: one for mouseover and one for mouseout. Here, on mouseover we clear the interval that is playing the slideshow and on mouseout we reset the interval to play the slideshow again. This should work to pause the slideshow when you hover your mouse over it.

    Hope this works out for you, good luck!

  27. Nick Says:

    Hi Jon,

    Thanks! Works fine in FF3, IE6 & 7, Opera and Safari on windoze. However, I noticed a problem in FF3 on the mac, where you have to click away from the window or elsewhere on the page (or refresh) to make the slideshow re-slide again, otherwise it stops on that particular slide. I presume it does the same on Safari on the mac.

    Although its a minor niggle and probably not much to lose sleep over (given the amount of mac users compared to windoze) but its still worth investigating for 100% usability across all platforms and browsers.

    :)

  28. Rick Says:

    This is just great :) Nice work. I think what would make it about perfect would be to have it pull the images from a directory. Possible? …My skills are limited, but I’ll give it a try…

  29. Dave Griffin Says:

    Hi,

    Just wanted to say this is an awesome slideshow solution, super simple but exactly what I have been looking for. As the other dudes have been saying in the comments lots of ‘other’ plugins are just too complex for my simple little brain.

    This will now be used on my new photography portfolio website.

    Thank you very much.

    Dave

  30. Nick Says:

    Rick - You can use php to grab all the images from a particular folder and put that in the div where the slideshow goes.

    A basic php script that pulls in the files from a particular folder for you to start off with -

    <?php
    $dir = “images/”;
    $dh = opendir($dir);
    while (($file = readdir($dh)) !== false) {
    echo “”;
    }
    closedir($dh);
    ?>

  31. Jon Raasch Says:

    Hi Rick and Nick,

    A script to pull the images from a directory sounds like a great idea, but let’s not involve PHP at this level. (Right now the slideshow works in basic HTML or any backend language). Instead look to jQuery’s very easy to use ajax() method. This could be used to hit Nick’s PHP page..but let’s also build in some recursion, in case the directory contains subdirectories.

    Good luck and if anyone gets this going, please post!

  32. Brad Blogging.com - Personal Blog Tips And Blog Help Says:

    You’ve got some link love.. Great job on making a lightweight and easy to use slideshow:

    9 Jquery Slideshow Applications You CANNOT Miss

  33. Adrian | Rubiqube Says:

    I keep getting “$active.next is not a function”. If I do an alert($active) it returns false. For some strange reason, the selector on line 2 doesn’t seem to work (works outside the function though).

    Any ideas?

  34. pavlentij Says:

    Great idea!
    Thanks!

  35. Jon Raasch Says:

    Hey Adrian,

    If I had to guess, I’d say you are either not loading jQuery or not defining the $active variable. Also try console.log() in Firebug instead of alert(), it will give you more meaningful results.

    Good luck!
    -jr

  36. Bart Says:

    Thx for the great article. Easy to implement!

  37. Saurabh Says:

    Wow ! simple and esay way to do the slideshow…
    Thanks for this slideshow, its almost what was I’ve been looking for.

  38. Cory Says:

    I’m trying to use your script above but instead of on img’s i’m using it on divs. It works great in FF but unfortunately in IE7 it produces an error. Here’s my code:

    a link to the example i’m trying to use is:
    http://dad.corydorning.net

    any help is greatly appreciated!

  39. Julian Says:

    Is it possible to have a different duration for each slide? E.g. slide #1 appears for 2 seconds, slide #2 appears for 4 seconds?

  40. r-doll Says:

    Thanks for this, its great. :)

    Like Helmut, I had varying sized images, so also set width/height on #slideshow also added overflow:hidden; to ‘trim’ down images to fit.

  41. eric Says:

    Thanks for your efforts, Helmut. This worked great and was by far the easiest jquery slideshow that I found to implement.

  42. Tom Says:

    Excellent simple solution, ive got one problem and cant seem to find where the problem is, in FF3 - Chrome - Safari it works perfect, images and fades in correct order, I have tried it on IE7 and it works ok, but starts on the last image and misses the first image out in my sequence? any ideas?

  43. Tom Says:

    dont worry forget that last post, ive found the problem, I had forgot to close off the div tag… it works perfect. excellent

  44. Tolis Says:

    Thanks for the wonderful tutorial. I wonder if it is possible to go to a specific slide when you click a thumbnail.

  45. Alex Sharp Says:

    Thanks for the great post and solid explanation of what’s happening throughout the code. I created a simple rails plugin that utilizes this code. “Here’s the link”:http://github.com/ajsharp/jquery_rails_slideshow/tree/master. Thanks again!

Leave a Reply

jr

Copyright © 2006-2008 Jonathan Raasch | Proudly powered by WordPress

Home | Web Design | Illustration | Paintings, Drawings | Graphic Design | 3D Art | Blog | Contact