Need some help?

I'm usually available for small jobs or problem solving with jQuery or css, at reasonable rates. Just get in touch.

Web Hosting

We recommend Clook for web hosting. UK based, great service and great value.

Buy me a drink

If you've found this useful, particularly for commercial projects, you might consider making a small donation.

jQuery image and caption slider

Been thinking for a while about putting together a slider where the image animates left to right and the accompanying text animates up and down. I wanted a slider that would allow the following:

  • Allow the html to be easily added – image and then caption as you would naturally add it
  • Allow more than one paragraph in the caption
  • Nicely degrading if javascript is disabled

So here it is…

The demo

Dingle Peninsula, Ireland

Dingle Peninsula, County Kerry, looking northward from Clogher Head

Sunset on beach

Sunset on the waves, near Fanore, County Clare

Bee

A bee.

Managed to get the focus just right on the wing and head.

Sparrowhawk

A sparrowhawk in our front garden.

Just out of shot is the racing pigeon she’s just caught and killed.

St Ives at sunset

Sunset over St Ives, Cornwall

Frog

A frog in our garden pond.

Here is a standalone demo too.

The code

This needs a fair amount of css, in part to make sure the page displays OK in the absence of javascript. Amend the width and heights to suit your own images.

#slider{position:relative;padding:10px;height:150px;width:760px}
#slider img,#slider div{display:none}
#slider img.active,#slider #slider_box{display:block;position:absolute;left:10px;top:10px;width:500px;height:150px}
#slider div.active, #slider #caption_box{display:block;position:absolute;left:560px;top:10px;width:170px;height:150px;}
#slider img{position:absolute;}
.caption p{margin-top:0}

#slider #slider_box{overflow:hidden}
#slider #slider_images{position:absolute;left:0;top:0;display:block}
#slider_images img{display:block}

#slider #caption_box{overflow:hidden}
#slider #slider_captions{display:block;position:absolute;left:0;top:0}
#slider #slider_captions div{display:block;height:150px}

And here’s the javascript. With a lot of images, you could call this using $(window).load() just to make sure all the images have loaded before the first animation occurs, but with a few small images it should be OK anyway.

var imageWidth = $('#slider img:first').width();
var captionHeight = $('#slider img:first').height();

//wrap the first image in divs for the slider
$('#slider img:first').wrap('<div id="slider_box"><div id="slider_images">').removeClass('active');
var countImages = 1;//initialise an image counter
//for each remaining image, move it into the slider_images div, stacked up left to right, and unhide it
$('#slider > img').each(function(){
	$(this).insertAfter('#slider_images img:last').css({'left':imageWidth*countImages+'px'}).show();
	countImages++;
});	
//clone the last image and put it at the front
$('#slider_images img:last').clone().prependTo('#slider_images').css({'left':-1*imageWidth+'px'});
//clone the first image (now the second image after the previous operation) and put it at the end
$('#slider_images img:first').next().clone().appendTo('#slider_images').css({'left':countImages*imageWidth+'px'});

//wrap all the captions into divs for the slider - use wrapAll now as the captions are now adjacent in the DOM
//we don't need to position the captions absolutely as they'll naturally stack up vertically
$('.caption').wrapAll('<div id="caption_box"><div id="slider_captions">');
$('div').removeClass('active');
//clone the last caption and put it at the front
$('#slider_captions .caption:last').clone().prependTo('#slider_captions');
//move the slider_captions div up so that the first caption is still visible
$('#slider_captions').css({'top':-1*captionHeight+'px'});
//clone the first caption (now the second after the previous operation) and put it at the end 
$('#slider_captions .caption:first').next().clone().appendTo('#slider_captions');

//find the height of the content of each caption and apply a top padding to the first element so the caption is vertically centred
$('.caption').each(function(){
	var contentHeight=0;
	$(this).children().each(function(){
		contentHeight += $(this).outerHeight(true);
	});
	$(this).children().first().css({'paddingTop':0.5*(captionHeight-contentHeight)+'px'});
});	

doSlide = function(){//recursive function that carries out the animation
	
	var newLeft = $('#slider_images').position().left-(1*imageWidth);//calculate the new position which is the current position minus the width of one image
	$('#slider_images').animate({'left':newLeft+'px'},'slow',function(){//slide to the new position...
	 if (Math.abs(newLeft) == ((countImages)*imageWidth)) //...and if the slider is displaying the last image, which is the clone of the first image...
		{
		$('#slider_images').css({'left':0});//...reset the slider back to the first image without animating 
		}
	 });
	 
	var newTop = $('#slider_captions').position().top-(1*captionHeight);//calculate the new position which is the current position minus the height of one caption
	$('#slider_captions').animate({'top':newTop+'px'},'slow',function(){//slide to the new position...
	 if (Math.abs(newTop) == ((countImages+1)*captionHeight)) //...and if the slider is displaying the last caption, which is the clone of the first image...
		{
		$('#slider_captions').css({'top':-1*captionHeight+'px'});//...reset the slider back to the first caption without animating 
		}
	 });		 
	setTimeout(doSlide,4000);	
};

setTimeout(doSlide,4000);
	

The logic

On load, only the image and the caption with class of active are displayed. Then I’m starting the code off by manipulating the html to stack all the images in a div, absolutely positioned so that they display in a horizontal row, and similarly with the captions to stack them in a column. Then I’m cloning the first and last images and the first and last captions and adding them back in to the html so that both appear to slide endlessly – I’ve used precisely the same approach as in the basic endless slider . Then I’m simply animating both the image and the caption via setTimeout

I’ve tested in FF3/5/7, Opera 11, Chrome, Safari 5 and IE6/7/8/9, all on Windows 7.

Can I use this on my site?

Probably. See my policies on using code from this site.

Useful? Interesting? Leave me a comment

I've yet to find a way of allowing code snippets to be pasted into Wordpress comments - so if you're trying to do this you'd be better off using the contact form.