jQuery Photo Slide Show with Slick Caption Tutorial Revisited

Written by Kevin Liew on 16 Dec 2009
266,266 Views • Tutorials

Introduction

If you have been reading my website from the start you would have read this tutorial:

Simple jQuery Image Slide Show with Semi Transparent Caption

It's a very famous post because it has been showcased in several major web design blogs so many times and I received a lot of traffic from it. Thanks guys. I get a lot of comment and as I replied to those comments and do some quick fixes, I realized that this script has a caption bug and inefficient and not up to standard (oh well, that's the time when I was start picking up jQuery :)), so I have decided to do revisit to solve all those problems discovered by readers. I rewrote the html structure and modify the script.

Mission Objectives:

  • Restructure the HTML, more semantic
  • Fix the caption bug, it displays the next caption too fast
  • W3C standard compliant, using appropriate attribute to store title and description
  • Cross Browser - Chrome, Safari, IE6, 7, 8 and Firefox.

However, one thing though, it needs javascript, if your browser is javascript disabled, sorry, there is no graceful degradation for this script, it will just display the first item.

Advertisement

1. HTML

Yes, I'm using list this time :) This is how it should have been afterall. No more REL attribute, we wil be using TITLE Attribute to store the heading and ALT attribute to store the description. For the caption elements, it will be added using jQuery. So, this is it - a clean and simple HTML code.

<ul class="slideshow">
	<li class="show"><a href="#"><img data-src="images/s1.gif" width="450" height="200" title="Slide 1" alt="Short Description"/></a></li>
	<li><a href="#"><img data-src="images/s2.gif" width="450" height="200" title="Slide 2" alt="Short Description"/></a></li>
	<li><a href="#"><img data-src="images/s3.gif" width="450" height="200" title="Slide 3" alt="Short Description"/></a></li>
</ul>

2. CSS

CSS code is rewritten completely. I guarantee it's cross browser compliant. They all look identical and it works great :) I did learn a lot of CSS technique through this blog. We all can improve our skills through tips, tricks, trials and errors. Read these posts to learn more about CSS:

body {
	font-family:arial;	
	font-size:12px;
}

ul.slideshow {
	list-style:none;
	width:450px;
	height:200px;
	overflow:hidden;
	position:relative;
	margin:0;
	padding:0;
	
}	

ul.slideshow li {
	position:absolute;
	left:0;
	right:0;
}

ul.slideshow li.show {
	z-index:500;	
}

ul img {
	border:none;	
}

#slideshow-caption {
	width:450px;
	height:70px;
	position:absolute;
	bottom:0;
	left:0;	
	color:#fff;
	background:#000;
	z-index:500;
}

#slideshow-caption .slideshow-caption-container {
	padding:5px 10px;	
	z-index:1000;	
}

#slideshow-caption h3 {
	margin:0;
	padding:0;	
	font-size:14px;
}

#slideshow-caption p {
	margin:5px 0 0 0;
	padding:0;
}

3. Javascript

We will going to use call back function to display caption. This will solve the "Caption Is Appearing Before The Next Slide Syndrome" :). Not too much of changes in javascript but I do added a feature though. On mouse over the slide will pause, and resume it back on mouse out. I think it's a good touch.

$(document).ready(function() {		
	
	//Execute the slideShow, set 4 seconds for each images
	slideShow(2000);

});

function slideShow(speed) {


	//append a LI item to the UL list for displaying caption
	$('ul.slideshow').append('
  •  
'); //Set the opacity of all images to 0 $('ul.slideshow li').css({opacity: 0.0}); //Get the first image and display it (set it to full opacity) $('ul.slideshow li:first').css({opacity: 1.0}).addClass('show'); //Get the caption of the first image from REL attribute and display it $('#slideshow-caption h3').html($('ul.slideshow li.show').find('img').attr('title')); $('#slideshow-caption p').html($('ul.slideshow li.show').find('img').attr('alt')); //Display the caption $('#slideshow-caption').css({opacity: 0.7, bottom:0}); //Call the gallery function to run the slideshow var timer = setInterval('gallery()',speed); //pause the slideshow on mouse over $('ul.slideshow').hover( function () { clearInterval(timer); }, function () { timer = setInterval('gallery()',speed); } ); } function gallery() { //if no IMGs have the show class, grab the first image var current = ($('ul.slideshow li.show')? $('ul.slideshow li.show') : $('#ul.slideshow li:first')); //trying to avoid speed issue if(current.queue('fx').length == 0) { //Get next image, if it reached the end of the slideshow, rotate it back to the first image var next = ((current.next().length) ? ((current.next().attr('id') == 'slideshow-caption')? $('ul.slideshow li:first') :current.next()) : $('ul.slideshow li:first')); //Get next image caption var title = next.find('img').attr('title'); var desc = next.find('img').attr('alt'); //Set the fade in effect for the next image, show class has higher z-index next.css({opacity: 0.0}).addClass('show').animate({opacity: 1.0}, 1000); //Hide the caption first, and then set and display the caption $('#slideshow-caption').slideToggle(300, function () { $('#slideshow-caption h3').html(title); $('#slideshow-caption p').html(desc); $('#slideshow-caption').slideToggle(500); }); //Hide the current image current.animate({opacity: 0.0}, 1000).removeClass('show'); } }

Updates

2010-09-10: Thanks to Rezzie who nailed the IE8 issue! :)

Updated the article and scripts, the link issue is fixed. :) Sorry for the delay.

Speed Issue

This is one of the issue that has been haunted me for a while, but thanks to Sam, one of our reader, he pointed out this would solve the issue, but with mixed result in IE.

Sam's solution, you need to add this:

$(window).focus(function () {
	timer = setInterval('gallery()', speed); 
});
$(window).blur(function () {
	clearInterval(timer);
});

James Burnett's solution, you modify the gallery function():

function gallery() {
	var current = ($('ul.slideshow li.show')? $('ul.slideshow li.show') : $('#ul.slideshow li:first'));

	if(current.queue('fx').length == 0) {
		
		// grab next image and animate code in here
		......
		......
		......
		
	}
}

Also, did some research, found the reason why it's doing it: From jQuery Animate Documentation: Because of the nature of requestAnimationFrame(), you should never queue animations using a setInterval or setTimeout loop. In order to preserve CPU resources, browsers that support requestAnimationFrame will not update animations when the window/tab is not displayed. If you continue to queue animations via setInterval or setTimeout while animation is paused, all of the queued animations will begin playing when the window/tab regains focus. To avoid this potential problem, use the callback of your last animation in the loop, or append a function to the elements .queue() to set the timeout to start the next animation.

Sorry guys, I don't have time to put all these together. Please let me know it works.

Randomize Slides

Simple yet effective solution from another reader - Blastos

Before the ending of function slideShow(), put this in:

//Generate a random number
var randNum = Math.floor(Math.random() * $('ul.slideshow li').length);

//Randomly pick up a slide
$('ul.slideshow li:eq('+randNum+')').addClass('show');

Caption doesn't appear for the first slide

I think it has to be the ommitted A tag for some users. Ammended the script, it should be fixed now.

Conclusion

I have made a lot of tutorials, and I think it's good to do a revisit to make it more efficient and solve some of the annoying bugs instead of quick fixes. So, yea, from now on, I will check my previous tutorials and rewrite them. :)

Like this tutorials? You can express your gratitude by visiting my sponsors on the sidebar, bookmark it and help me to spread this tutorial to our friends! :) Thanks!

Demo Download
Join the discussion

Comments will be moderated and rel="nofollow" will be added to all links. You can wrap your coding with [code][/code] to make use of built-in syntax highlighter.

488 comments
Scott 15 years ago
Love this little gallery. Is is possible to turn the captions off? I have images but don't the captions as all. What would you suggest?
Reply
Kevin Liew Admin 15 years ago

if (desc) {
//Hide the caption first, and then set and display the caption
$('#slideshow-caption').slideToggle(300, function () {
$('#slideshow-caption h3').html(title);
$('#slideshow-caption p').html(desc);
$('#slideshow-caption').slideToggle(500);
});
} else {
$('#slideshow-caption').hide();
}

try that, basically if the desc is empty, hide the caption, otherwise, show it.
Reply
nicola 15 years ago
nice plugin...
but... can i place more istance of slideshow in the page?
thanks
Reply
Abdul Rafy 15 years ago
you found out?
Reply
Colin 15 years ago
Hi, great slider and it works like a breeze. I have one question though. I have drop down menus along the top and when they drop down they are behind the slide show. How do I fix this? Thank you.
Reply
Kevin Liew Admin 15 years ago
Must be the z-index: You need to find the CSS for the drop down menu and change the z-index value to something larger than 500.

OR

you can change this z-index value to something lower than the z-index of the drop down menu:

ul.slideshow li.show {
z-index:500;
}
Reply
ingEEnius (aka TheloniusMonk) 15 years ago
Hi Kevin,

Firstly great slider and tutorial. Works like a treat and the semi-transparent caption adds a great touch. I'll definitely be subscribing to this blog.

Now on to the problems I'm having...

I have added 6 images and 6 corresponding captions just to test things out a bit. The captions seem only to show for the first 3 images, after this they don't show.

That is the captions for the first 3 images will show with their corresponding images. Following this, the rest of the images ( 4, 5, and 6) will show albeit without their captions.

The images then loop back to the first continuing to scroll through the image set but with no captions this time round.

So on the first run i.e page refresh, the first 3 images and their captions display. The captions then drop off for images 4,5 and 6. The slide loops back to the 1st image and slides through the image set again but this time there are no captions on any image. This happens for subsequent iterations, until page refresh that is...

Is there a fix? I'd like to be able to display up to 10 images all with captions. Look forward to seeing what you think.

Thanks in advance
Reply
ingEEnius 15 years ago
Hi Kevin, me again.

Okay I think I've got it working right now (let's hope I haven't spoken too soon..eeek!)

It was just my being careless with the markup.

Great tutorial once again. I'll be keeping an eye out for new developments.

Keep the blog going solidly, you're doing a great job here ;-)

Regards.
Reply
Tara 15 years ago
Does anyone know why the first caption wouldn't show? The grey box is there, just not the text and after it completes a full cycle, the text is there.
Reply
Kevin Liew Admin 15 years ago
Have you tried the demo I have? Did it appear?
Reply
Fabiana 15 years ago
I'm having this same problem. Trying to figure what it's happening.
Reply
Tara 15 years ago
It does show up in the demo but as soon as I put it in my personal sight, it doesn't work right. I'm not sure if it is because of all the other css I have or what.
Reply
Kevin Liew Admin 15 years ago
Possible. I think the best way to find out is - make a working version then out in your website code bit by bit. You should able to find out the actual source tht causing the problem.
Reply
Stuart 15 years ago
Hi, Great script and exactly what I needed but I'm getting the same problem with the 1st description not showing. The demo doesnt do it and I've rebuilt several times but still getting the same problem. Has anyone worked out the issue?
Reply
kate 15 years ago
Hi all,
I had the same problem. I realized when scanning through the code that I had removed the <a> tags since i didn't want links and this line:
//Get the caption of the first image from REL attribute and display it
$('#slideshow-caption h3').html($('ul.slideshow a:first').find('img').attr('title'));
$('#slideshow-caption p').html($('ul.slideshow a:first').find('img').attr('alt'));

is calling for the 'ul.slideshow a:first'

I added an <a href="#"></a> back on that first <li> and the caption reappears.

Hope this helps.
Reply
Kevin Liew Admin 15 years ago
hmm, this is so weird. What doctype are your guys using? If you copy my demo and put it in your website, does it work?
Reply
Neil Hodges 15 years ago
Hi Great tut,
im using several images with your slider and it works great,
the only problem i have is the anchors wrapped around the images, each image has a anchor pointing to a different page, but when i click on any image it uses the last anchor tag and send me to that page.
Its like it ignores the anchor tags and just uses the last anchor in the set of images?
any ideas?

Kind Regards

Neil.
Reply
Kevin Liew Admin 15 years ago
this shouldn't happen, does the demo did the same?
Reply
Chris 15 years ago
Great slideshow and simple to install thank you very much! Is it possible to include like a "forward" "back" button or small buttons that make it possible to click in them and get the according image (small 1,2,3,4...) ?
best regards, Chris
Reply
Kevin Liew Admin 15 years ago
Hi Chris, you can't do that in this slider. If you need something like that, check out Nivo Slider, it's my favourite slider, heaps of configuration and it meets your requirement.
Reply
Chris 15 years ago
Me again, I´m sorry for the spam I didn´t see the green comment info last time and tried to implement this additional feature with my tiny jquery skills which didn´t work out yet...
best regards, Chris
Reply
Dan 15 years ago
Thanks for this script. Its a neat piece of kit.

One problem I have is that I am running it with another jQuery feature called fancybox. This is just a variation on light box, which shows an image (or other file eg.swf) in it's own frame whist dulling the browser window.

If I click a link which uses fancybox and the title panel is animating downwards, the link opens as it should, but when I close it, the title panel freezes where it was (nearly out of view). The image slideshow is unaffected. As I said, this only happens when the title panel is animating downwards (when it is changing).

Can anyone shed any light on this problem? Thanks in advance if you can.
Reply
Kevin Liew Admin 15 years ago
hmm, that's interesting... i wont have a clue in this matter unfortunately :(
Reply
Steve Grondin 15 years ago
Hi this Slider is very nice but i really dont know how to put it automatic at startup... at the moment my slider began only when i put my mouse over the slide... and it pause it when i put my mouse back... i want it automatic all the time like in continue with no pause :) Thanx for your help and sorry my english i speak french.
Reply
Kevin Liew Admin 15 years ago
That's weird, do you have this code:

$(document).ready(function() {

//Execute the slideShow, set 4 seconds for each images
slideShow(2000);

});

that will load the slider once the page load and execute automatically.
Reply
Christina Papandrea 15 years ago
Hi there!
I'm having issues with the code: I dropped everything in exactly as you've structured it on your demo page, the only items i changed were the src locations for the image files, and the image sizes (width x height). However the slide is not working, it is only pulling in the first image but no caption or title. I'm sure I've overlooked something but I just can't seem to see what...Help?

Thanks!
Reply
Kevin Liew Admin 15 years ago
Have you pust class="show" in the first li?
Reply
Jess 15 years ago
I'm having the same problem, did you work out what you were doing wrong? thanks
Reply
Jessica 15 years ago
HI there -- thank you for the script. How do I have it NOT go on automatic loop -- if I only want cycle of images to show? thanks!
Reply
Kevin Liew Admin 15 years ago
not sure how to do it. but the concept is to detect the last item, and then stop the script.

this will stop the script: clearInterval(timer);

alright, should look something like this, i haven't tested it, but put this in line 50.

if ($('ul.slideshow li').length - 1) == next.index()) clearInterval(timer);
Reply