Simplest jQuery Slideshow
A friend was looking at doing a simple slideshow. The requirements were very straightforward:
- No animation controls. eg: play, stop.
- Images should cross-fade.
Her instinct was to find an existing jQuery plug-in and revise it to work to her needs. That would seem simple enough but if you do a search for jQuery slideshows, you'll find that there are plenty of them and they are filled with plenty of functionality.
Using an existing plug-in wasn't very practical and hard to work with. I had even recommended a script that I, myself, had written but she quickly realized it didn't meet the requirements.
I put my thinking cap on and decided to write a script from scratch. "Under 20 lines," I exclaimed! In the end, it turned out much simpler than even I predicted.
(If you're a TL;DR kinda person, check out the demo.)
HTML and CSS
The HTML was very straightforward: a DIV with some IMGs in it.
<div class="fadein">
<img src="https://farm3.static.flickr.com/2610/4148988872_990b6da667.jpg">
<img src="https://farm3.static.flickr.com/2597/4121218611_040cd7b3f2.jpg">
<img src="https://farm3.static.flickr.com/2531/4121218751_ac8bf49d5d.jpg">
</div>
In thinking about the CSS, I decided to just lock all the images into the same place using absolute positioning.
.fadein { position:relative; width:500px; height:332px; }
.fadein img { position:absolute; left:0; top:0; }
jQuery Slideshow
Now to think about the slideshow. First, I knew that I'd want to hide all the images except the first one.
$('.fadein img:gt(0)').hide();
You have to remember that the image index starts at 0. That means that we want all images after the first one to be hidden.
Next, I need a setInterval
to iterate through the images every few seconds.
setInterval(function(){ },3000);
From here, I started writing this out piece by piece to get what I wanted. I needed the first image to fade out.
$('.fadein :first-child').fadeOut()
After that, I need the next image to fade in.
.next('img').fadeIn()
Then I needed to take the first image and throw it onto the end of the stack.
.end().appendTo('.fadein')
The end()
resets jQuery's internal reference back to the original selection. That way, it's the :first-child
that I'm appending to the end of the .fadein
element and not the next('img')
.
That's it?
Well, yes. That's it.
$(function(){
$('.fadein img:gt(0)').hide();
setInterval(function(){
$('.fadein :first-child').fadeOut()
.next('img').fadeIn()
.end().appendTo('.fadein');},
3000);
});
Check out the demonstration page to this this little script in action.
Is there an even simpler way to do this? (Some ideas that I haven't tried: Is specifying img
in next()
necessary? Could I have used eq(0)
instead of :first-child
to save a couple bytes?)
For more Snook.ca slideshows:
Conversation
:) Even the post is concise, loving it! Thank you again sweetness.
Looks really similar to what we did on http://pocketyoursite.com, but yours is more elegantly coded. :) Mine is additionally ugly because I had to sync two "shows" and ended up just doubling up the code...
Impressive!
I guess you could indeed use
eq(0)
instead of:first-child
in most cases. (Depending on how many of these slideshows you would want on one page, and how you’d specify the different element sets on which to invoke the effect,:first-child
andeq(0)
could return different results.)Specifying
img
innext()
is something I personally wouldn’t do, since I’d be using an unordered list containingIMG
elements. Fade effects work on any HTML element, so there’s no problem there. Dropping theimg
innext()
wouldn’t just make your script smaller, it would increase its flexibility by accepting different markup scenarios.Great work Jonathan, however when Javascript is disabled you can only see one image. Would it not be better to perhaps set the images to overflow:auto so at least the user could scroll through the images if they didn't have Javascript?
good job - i got the perfect use for this!
Wow, what a nice slideshow. This can help lots of people with no jQuery knowledge. No need to add anything else. Nice job.
I was prepared with a "why not use Cycle lite" comment, but then I saw how little code you used to pull this off. Very cool!
Sweet Jonathan. I love when code is nice and small. Will definitely check this out next time I need slideshow functionality. Thanks for sharing :)
Hey Jonathan, nice to have met you in Amsterdam!
If you rearrange the images to be in reverse-order, you can fade with basically just one line of code. For a cross-fade it's just necessary to fade out the overlaying object (you don't need to fade two elements at the same time).
Here's my implementation with Prototype and scriptaculous, with three lines of code. :)
By the way, I love the comment preview functionality on your site.
Sweet! I use Alsup's cycle all the time and it works great. but this takes the cake from a simplicity standpoint. Thanks!
Jonathan, your code can easily be made into a jQuery plugin:
Now you can use something like this to invoke the slideshow on an element:
As you can see, I’ve added a
timeOut
parameter. The default value is3000
(I just took this from your code) but this can easily be specified:I uploaded an example of your script in this plugin format.
I also did the changes I mentioned in my first comment, allowing for more flexibility in the markup. Here’s an example of your script cycling through an unordered list.
I had a pretty big bug in my code, but have corrected it now (unfortunately, requires some extra hoops). Anyway, here it goes:
I personally don't like either the jQuery (too "magic", not readable) nor my code (too complicated). Will think about it and hopefully come up with something nicer.
Thanks for the food for thought!
If you ignore the opening and closing function call and don't bother to specify 'img' for next(), the minified version of this is exactly 140 characters. Any jQuery function that both does something useful and fits inside a single tweet is something to be proud of.
@Steve Rydz - I would think that you'd want to hide the other images, otherwise it could break the layout of the page (depending on how the images fall into place).
Other way's I've seen this done (though not using Snook's methodology) is that in the HTML you only specify one image and use JS to append the other images to use in the slideshow. If the user has JS disabled, they only see the one, placeholder image. This is kind of the same, except that the JS isn't adding the other images... they're specified in the HTML.
Bravo snook! I'm really liking this! Is there some way to control how fast the image fades out? Would you do that by extending the interval time?
Thomas - I agree in a way regarding the jQuery syntax...
The enthusiasm for code like this makes me anxious. Don't get me wrong, it's beautiful... It's just that I've had one to many experiences working with really cool and terse jQuery "sream of consciousness" style code. Also, I hate the misconception that this is just a few lines of code. It's a few lines of code plus the jQuery library. Readability and performance gains seem to be canceled out here in a way.
It just upsets me when I imagine the complex web app that's written entirely like this because a developer gets too excited about how few lines of code something might take instead of making something understandable and scalable.
With that said, this is a really cool post! I look forward to more, and I'm really loving the redesign here...
@Jeff: to change the speed at which the fade occurs, you need to pass in a parameter to the fadeIn/fadeOut methods.
"Too magic to understand" strikes me as a bizarre criticism of what is a relatively simple code snippet that a majority of jQuery developers could grok in a matter of seconds. Jon's example is clearly only a few lines of code, there is no "misconception" there. LOC is not calculated by adding up all the lines of code that are used in the library methods that you employ in the original function.
There is a lot of energy invested on large jQuery sites on organising and structuring code (or at least there should be), so the idea that someone would write a "complex web app" as a random bunch of jQuery snippets seems like an unfounded fear. It does happen, but unsavvy developers writing crappy code is not a problem that is unique to jQuery or even JavaScript. I have frequently encountered this perception that jQuery is "too easy" from a lot of people who tend to conflate complexity with worthiness, and I just don't buy it. That the potential exists for something to be misused does not mean it should be eschewed altogether.
I shudder at the thought of seeing this code written out with native DOM methods, and I shudder again at the thought that someone that would be preferable.
I love the simple slideshow concept here. But I notice that all the images are the same size in the slideshow. Does anyone have an example of showing both landscape and portrait photos in the same slideshow with the portrait photos centered? All photos would be the same height, but of course the portrait photos would have a smaller width.
Thanks!
@Daniel Marino That is one way.
Surely however the images must be relevant to the content and therefore should be accessible. Having them hidden or positioned absolutely on top of each other means that in the situation where JS isn't available the user cannot access the images at all except whichever one is on top.
The only way I can see this being acceptable is if the images are there purely for decoration but then they wouldn't be in the content, they would be specified in the stylesheet.
I'm glad someone else pointed out that this "tiny" piece of code requires the entire jQuery library behind it. I know there's a judgement call to be made - when to stop writing custom code and use a library - but a novice doesn't know about that.
I'm not arguing against jQuery or Jon's code - I just think that, in general, its a good idea to mention an alternative to using a framework, in case a reader only needs the functionality you're describing. Otherwise a novice is going to follow a Jon's article and end up using a sledgehammer to crack a walnut.
@Adam Sontag
Writing a custom script to do the same isn't hard - I recently wrote something very similar for a client that comes in well under 1k uncompressed. There are plenty of occasions where going native is preferable.
I have written a "fully-fledged" (e.g. chainable) jQuery plugin based on the ideas above. It can be called with timeout and speed parameter values.
You may use it like this:
BTW: It's still less than 20 lines!
Graceful degradation: When the slideshow is initialized, add a second class to
.fadein
, and reference the js-dependent css using that class. Also, might as well just get all direct children of.fadein
. The simple slideshow is inconstent betweenimg
and:first-child
, so that's basically a requirement anyway. While we're at it, why not store$('.fadein')
via closure?This would be incredibly easy to turn into a function to allow multiple slideshows on a page.
Thanks Michaël, I was about to update my ‘plugin’ example with that functionality (speed setting + chainability).
I see you wrapped the code inside
this.each(function() { … }
, so it works for several elements at the same time. Awesome!I took the liberty of adding this to GitHub, so it’s easier to reference future improvements of the script. I hope that’s okay.
Dude that is so clean. Two lines??? That's why you're the man, Snook!
Mathias, How do you change the fadeIn, fadeOut animation with your code?
I like the fact that you show us how to do it instead of just providing a plug in. Awesome tutorial.
@Steve Rydz: If you're looking for a non-JS alternative, I'd look at attaching a "with JS" class at runtime. With that said, when talking about accessibility, those with screenreaders and other assistive software usually browse with JavaScript on. Which still begs the question of how the interaction should work when there's no real interaction at play.
What I'd recommend is having the images fade in/out but set visibility to hidden and display set to block (do not set it to none). Make sure the images have alt text. That should still allow screenreaders to access the content regardless of the animation.
I think you misunderstand me Jonathan. I mean more of a situation where someone is viewing the site without Javascript but not assistive technology.
For example I used to work in an office and we had free reign on the web in quiet times but were not able to use JS, so in a situation like this I would only be able to see one image and not even have the option to scroll through the other images.
This might work from a presentation point of view however if the images are in the content then surely they should be available without JS?
This is more of a CSS thing than JS really. I hope you get what I mean?
Right, I understand now. In which case, I'd do as mentioned in previous comments and as I mentioned in the first sentence of my comment: just add a class to the body or to the surrounding element via javascript and use that to set the absolute positioning.
Ah I get what you mean now. Sorry I was on a completely different wave length. You live and you learn ;-)
@MATHIAS BYNENS: Thanks for putting it on GitHub. Just one more thing: According to the jQuery plugin guidelines the name of the (plugin) file should be "jquery.simplestslideshow.js" (or "jquery.slideshow.js", but I prefer the first).
Just to be clear: it’s not 'my code', I just wrapped Jonathan’s code into a plugin with some enhancements from Michael. Credit to these fella's!
To answer your question: sorry, that’s not what this script does. As Jonathan explained, this is just a simple slideshow where images cross-fade. If you want more fade effects, use a (heavier) plugin, like Cycle or Cycle Lite.
Thanks for the tip, Michael, I renamed it.
I love how, after some optimizations, the minified plugin version of this script is only 291 characters long.
This is great! Thanks for explaining how it all comes together Jonathan.
Is there anyway to make this work with the same class for multiple slideshows on the same page?
Chris: This would be very easy using the plugin. Here’s an example of multiple slideshows (having the same class) in one page.
Thank you Mathias :D
Great post!
Instead of cross-fading two images you can also just get the first one, hide it, append it to the end of the image stack
and fade it in from there so that the (in this case white) page background won’t shine through.
Like this:
http://jsbin.com/isegi
It is a very simple slideshow. Useful for some projects.
I like the Christian Fleschlut solution.
Nice solution, Christian! Unfortunately your scripts starts off with the wrong image.
Christian: My latest comment was phrased incorrectly. Your example flashes the last image in the stack upon loading, then quickly switches to the first image. I found this to be pretty annoying. Also, note that Jonathan’s demo doesn’t have this tiny issue. This can be fixed through CSS (in combination with a ‘with JS’ class), and by adding some tweaks to your code. Currently, you have the following:
Try this instead:
As you can see,
.show()
explicitly makes the first image visible.Combined with the ‘with JS’ class, you can use CSS to hide all the images inside
.fadein
until the script makes them visible again:If you omit
.js .fadein img:first-child { display: block; }
, this will also cause a small ‘flash’, going from the background color of the page to the first image. This is better already – at least it’s not a ‘flash’ between two images. But by adding that line, we don’t get a flash at all :)Whoops, that last link should be http://jsbin.com/alada3. Jonathan, could you please edit my previous post and remove this one? Thanks!
Jonathan, I wrote a tiny plugin that does just this to help someone in the irc.freenode.net #jquery IRC channel earlier this year. What I did was very similar, except that it did allow stopping and restarting, as well as a "one-off" fade without any kind of loop.
I'm not a big fan of setInterval, for reasons explained on this doTimeout example page, so I've used setTimeout instead. The plugin code is available in the source of the 'fadeQueue ' example page.
This is one of this little plugins that got totally lost in the shuffle.. thanks for reminding me of it!
Amazing trick with such tiny amount of code, thanks for sharing.
It's funny that you posted this. I've been looking for a plugin to do exactly this. I'm still in the beginning stages of learning jQuery so I couldn't do it myself.
again, thanks!
I'm use this code with jquery tools slider. It seems conflict mixing with jquery tools because it only fade one time and then stop.
What solution for this?
Check out Slidedown.
It Generates syntax-highlighted slides from Markdown.
http://github.com/nakajima/slidedown
Good stuff Jonathan, you make it seem so effortlessly easy!
Forget my previous comment, I found the problem :]
Your code is running smooth right now, It's a miracle!
What
You would not believe how much time I have spent looking for something like this to solve my problem.
This should be the default setup for anyone looking for a photogallery solution
For a port to mootools, would be great to have that...
I was trying to make it work when each image is a link. Any suggestions? Thanks!
Wow. That's what I call lightweight. Thank you!
Just an idea... I tend to do jquery stuff completely internal; meaning, I also handle all CSS stuff using jquery, making the modding of yet-another-file (the css file) void.
I'm not sure if everyone will agree, but I am convinced that it strips some bytes from the main css and it only uses the jquery-needed css rules if the user has javascript enabled.
You might want to try it... it downgrades more beautifull and surely is a bit more minimal when those robots come haunting your site for more search-engine food.
Nice site btw. - and I sure like that "preview" while writing my comment. It simply rocks!
Love this script, use it on my own site! Thanks, if only all code was this concise!
Anyone know how to add links to the images or the whole thing?? Its exactly what i'm looking for if it had that!!
found a way to link the whole thing, not ideal but basically adding onclick to the surrounding div. If anyone has a cleaner way let me know: http://www.shore.co.uk/snow/snow-jackets/ladies-snow-jackets.html
It's quite easy to do. Just add a link around each image have the links fading back and forth instead of the images. The css would look something like this:
And the Javascript would look like this:
I am new to jquery and was wondering can anyone explain what the gt(0) in this line of code $('.fadein img:gt(0)').hide();
stands for?
How to do this with img's of different sizes?
@Cat: it means 'greater than' zero. That means get every image except the first one and hide it.
@Anthony: You can do all sorts of different sizes, you just need to make sure that you've reserved room for the largest image. If you wanted it to resize the space for each image, that's a little more complicated. You'd have to get the dimensions of the image and then resize the container around it.
Thanks for this although I'm having trouble with jquery 1.4.2 here: <http://www.hakomimallorca.com/about-mallorca>
It seems to skip through the images once then stops at the final one instead of looping.
Please disregard my previous comment...thanks
Sir, you are gentleman and a scholar.
I've been wrestling with slideshows of one kind or another for the last six ours trying to meet a deadline for a client. Everything else was breaking the layout with the styles being dynamically applied or the use of static positioning.
This was simple, clean, and elegant. Perfect.
A million thanks to you.
-Sam
I need to add a play/pause, forward and backward to this jquery. Could you please help me with this. Is it possible to do that? Can I use this code to my website. Is it legal?
Hi! I've been looking for a slideshow like this, but, at the same tiem i've downloaded a lot of them, by the way this one is the most practic one, congrats!!!, i would like to ask you a thing, why all of them are constructed with PA Divs and not with simple Divs??? If you could answer me i'll be very grateful.
THNKS!!!
@Daniel: What's a PA div and how does it differ from a simple div?
Nice one, very simple. Sometimes a whole library just isn't needed.
Great solution. Was trying to work out the neatest way to advance the slides with a mouse click (instead of via "set Interval"). Similar to the query from Anitha (above). Any ideas on this would be appreciated. I now there are many other slideshows out there, but having the images in a single div with a class is potentially great for use with a CMS.
I think Daniel is trying to say AP div. Absolute positioned div.
Thanks for the easy script.
I am unable to see this slideshow when i add jquerymobile css
Please help
thx for so simple & easy slideshow script.......plz help me in tab switching and drop down menu......thx in advance.
Just wanted to thank the creator for this simple slideshow, and for helping me learn how to make slideshows in general (web student for almost year and a half now).
Hi, thanks for the code. If I wanted to add a pause to the slideshow, so when a user hovers on an image the show pauses and on mouseout the show resumes how would I go about doing this?
I've tried adding onMouseOver and onMouseOut attributes but I'm not really a coder and haven't got very far!
AMAZING! Thank you so much :)
This is absolutely amazing, and exactly what I needed. I'm a newbie at js and jQuery, so please forgive the intro answer. Is there any way to randomize the order that the images are displayed in, while keeping the multiple slideshows on the same page? TIA!
One more question - yes, I'm still a newbie. Is there any way to adjust the timing on the slideshows so that they look like they are daisy chaining - so a second slideshow on the page starts a few miliseconds later than the first? TIA!
I thought it would be easy to find a clean-coded fade slideshow... boy was I wrong. I'm a novice at programming to begin with but after hours of searching I was really feeling like an idiot. Thanks so much for this script!!
Is there a way to randomize the images ??