Infinite Carousel Photo Gallery With CSS 3 & jQuery
As I said the original inspiration behind this gallery is now gone, but the idea is still there. The gallery was basically an infinite carousel showing one image in the center with 1 half showing either side. I remember looking at the code used for it & thought there must be a simpler way to do it as it seemed extremely complicated. Then I realized the code was quite old and jQuery has come a long way since then, so here is my version of that photo gallery.
Infinite Carousel Gallery: Concept
The idea seems simple, a carousel of images that you can flip left or right through. The infinite part comes into play when you reach the last image. How? Well, when you do reach the last image the next image you see is the first image again. This let’s you flip through all the images without reaching an abrupt end.
I like the whole illustrate with images thing I’ve had going on in the last tutorial or two, so let’s keep it going. First let’s see what we are going to make, and you can try it out by clicking the demo below that. Just remember you’ll need an up-to-date version of a modern browser to view it at it’s best.
Now that you can see what we are going to be making, and you’ve had a chance to try it out let’s look at browser support.
- Firefox 3.6 – Works with all features.
- Chrome 11 – Works with all features.
- Opera 11 – Works with all features.
- Safari 5 – Works with all features.
- Internet Explorer 8 – Animation works, however box shadow & scaling do not.
- Internet Explorer 9 (RC) – Works with all features.
One small note about Internet Explorer 9. You must use the correct DOCTYPE
or it will enter Quirks Mode & things will all go very strange. In HTML 5 you can use the DOCTYPE
shown in the demo that’s:
1 2 |
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> |
Now that we’ve looked at potential browser problems let’s get onto the code that runs this bad boy. 😉
Infinite Carousel Gallery: HTML
First onto the HTML. I like to try to keep the HTML as simple as possible so bearing that in mind here is what I ended up with.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
<div id="photos_container"> <div id="photos_inner"> <ul id="photos_ul"> <li><a href="#"><img src="/JPEG/001.jpg" /></a></li> <li><a href="#"><img src="/JPEG/002.jpg" /></a></li> <li><a href="#"><img src="/JPEG/003.jpg" /></a></li> <li><a href="#"><img src="/JPEG/004.jpg" /></a></li> <li><a href="#"><img src="/JPEG/005.jpg" /></a></li> <li><a href="#"><img src="/JPEG/006.jpg" /></a></li> <li><a href="#"><img src="/JPEG/007.jpg" /></a></li> <li><a href="#"><img src="/JPEG/008.jpg" /></a></li> <li><a href="#"><img src="/JPEG/009.jpg" /></a></li> <li><a href="#"><img src="/JPEG/010.jpg" /></a></li> <li><a href="#"><img src="/JPEG/011.jpg" /></a></li> <li><a href="#"><img src="/JPEG/012.jpg" /></a></li> <li><a href="#"><img src="/JPEG/013.jpg" /></a></li> </ul> </div> <div id="photos_nav"> <div id="photos_left"><img src="prev.png" /></div> <div id="photos_right"><img src="next.png" /></div> </div> </div> |
As normal you would replace the image paths, and the hyperlinks would point to the larger image. You’ll also need to provide a previous & next button although you can feel free to use the ones on the demo page.
A small, but very important, note is that your images must all be the same size. If they aren’t the CSS should auto resize them in proportion, however it looks neater if they are all the same size. It’s also best if they are all portrait images.
Infinite Carousel Gallery: CSS
There is quite a lot of CSS for this gallery, and a lot of it is needed for it to work properly. Let’s take a look and I’ll highlight the important lines.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 |
#photos_container { width: 754px; margin: 9% auto 0 auto; padding: 20px 0; } #photos_inner { width: 754px; overflow: hidden; } #photos_ul { position:relative; left:-566px; list-style-type: none; width:9999px; margin: 0px; padding: 0px; padding-bottom:10px; } #photos_ul li{ float: left; width: 297px; transform: scale(0.75); -moz-transform: scale(0.75); -o-transform: scale(0.75); -webkit-transform: scale(0.75); padding:0px; margin: 10px 40px; } #photos_ul li img { width: 267px; .margin-bottom:-4px; cursor:pointer; cursor: hand; border:15px solid #FFFFFF; box-shadow: 1px 1px 5px #555; -moz-box-shadow: 1px 1px 5px #555; -o-box-shadow: 1px 1px 5px #555; -webkit-box-shadow: 1px 1px 5px #555; } #photos_nav { width: 72px; margin: 0 auto; } #photos_left, #photos_right { float:left; height:36px; width:36px; } #photos_left img, #photos_right img { cursor: pointer; cursor: hand; } |
First we need to look at some very important numbers that need to be set in the CSS. Unfortunately this is where a bit of complicated Maths comes into play. I’ll try to keep it as simple as possible though.
- #photos_inner > width • Width of 1 list item (img + border) + left & right margin X 2
- #photos_ul > left • (1 list item + left & right margin) + (half 1 list item + left margin)
- #photos_ul li > width • width of 1 image + left & right borders
- #photos_ul li img > width • The width of your images.
Those are the important sums that must be worked out correctly. If they aren’t you’ll probably find your animation won’t work & things will look a bit… Strange.
Here is a list of the other important parts that you probably won’t have to change, but are needed by jQuery to work properly.
- #photos_inner > overflow • Hidden
- #photos_ul > position • Relative
- #photos_ul > list-style-type • none
- #photos_ul > width • Must be nearly infinite 9999px is near enough
- #photos_ul li > margin • Personal choice, but will help determine the values of the sums above
- #photos_ul li img > border • Personal choice, but will partly determine the list item width
Everything else in the CSS is to help make it look nice, and the CSS 3 rules like box shadow & transform are not needed but when viewed in a browser that supports them it add that little bit of extra spice.
Infinite Carousel Gallery: jQuery
Now for the meaty bit. The jQuery code. This can get a little complicated so my sister over at Lisa Marie Art & Illustration has kindly created some information graphics to help out with the explanation.
First though here is the code in it’s entirety.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
$(function() { /* START --- User Variables --- START */ var $car = $('#photos_ul'); /* END --- User Variables --- END */ var num_img = 3; var $offset = $($car).css('left'); var ctr_img = Math.round(num_img / 2); $('li:first', $car).before($('li:last', $car)); $('li:first', $car).before($('li:last', $car)); $('li', $car).scale(0.75); $('li:eq(' + ctr_img + ')', $car).scale(1); $car.css({'left' : $offset}); $('#photos_right img').click(function(){ var itemWidth = $('li', $car).outerWidth(true); var leftPos = parseInt($car.css('left')) - itemWidth; $car.filter(':not(:animated)').animate({'left' : leftPos}, 500, function() { $('li:last', $car).after($('li:first', $car)); $car.css({'left' : $offset}); }); $('li:eq(' + ( ctr_img + 1 ) + ')', $car).animate({ scale: '1' }, 500); $('li:eq(' + ctr_img + ')', $car).animate({ scale: '0.75' }, 500); }); $('#photos_left img').click(function(){ var itemWidth = $('li', $car).outerWidth(true); var leftPos = parseInt($car.css('left')) + itemWidth; $car.filter(':not(:animated)').animate({'left' : leftPos}, 500, function() { $('li:first', $car).before($('li:last', $car)); $car.css({'left' : $offset}); }); $('li:eq(' + ( ctr_img - 1 ) + ')', $car).animate({ scale: '1' }, 500); $('li:eq(' + ctr_img + ')', $car).animate({ scale: '0.75' }, 500); }); }); |
First a very important note. I animate the scale property here with jQuery, this is not natively available through jQuery and you will need to download the jQuery CSS Transform patch and the jQuery Animate for Rotate & Scale patch. You will also need to attach them after jQuery, and in that order. Huge thanks to Zachstronaut for making those patches.
Right, now let’s go through all this code piece by piece. I’ll ignore the DOM ready as it’s the same for most jQuery code.
1 2 3 |
/* START --- User Variables --- START */ var $car = $('#photos_ul'); /* END --- User Variables --- END */ |
This variable is one that could possibly need changing depending on how you are using the gallery. The only variable here is the path to the UL element containing the images. This can be customized freely. I have tried my best to make the code so that you will only need to change this single line if your UL has a different ID.
1 2 3 |
var $offset = $($car).css('left'); var num_img = 3; var ctr_img = Math.round(num_img / 2); |
The first variable here stores your original left offset from your CSS. This is needed to make the carousel work properly later during the animation stage.
The second variable is just to help with the next sum. It tells it how many images are visible at one time, this includes the two half images either side. This cannot be changed yet as the code will most likely break due to how the infinite part of the carousel works. I’m working on that though.
The last variable here works out which numbered image will be at the center by taking the number of images visible and dividing it by 2, and rounding it up. This works because an odd number of items halved will always give you the number of the center item if you round the resulting decimal up.
1 2 3 4 |
$('li:first', $car).before($('li:last', $car)); $('li:first', $car).before($('li:last', $car)); $('li', $car).scale(0.75); $('li:eq(' + ctr_img + ')', $car).scale(1); |
Now comes the actual code. From now on I use the variable set before $car
as context to select elements starting from the UL element we stored in the user variables earlier.
First we move the last two list items (images) to the front of the carousel. This is just in case the user presses previous first. This is partly the reason why you can’t increase the number of images displayed & needs to be looked at, but for the moment this is the best I’ve been able to come up with. I would have chained them, but for some reason they don’t work the same way & need to be two separate calls to before
.
Next we use our patches to scale all the items down to 75% their original size. We have already done that in the CSS, however that is just to stop the flash before the jQuery has loaded. For some reason the jQuery patch does not recognize that you have already set the scale via CSS, so you must set it again here so we can animate it later.
Now we use the scaling again to scale up our center image back to 100%. This gives a nice circular carousel effect to our gallery by making the image on the left & right smaller than the center image. It’s also a lot easier than saying scale all the images except this one.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
$('#photos_right img').click(function(){ var itemWidth = $('li', $car).outerWidth(true); var leftPos = parseInt($car.css('left')) - itemWidth; $car.filter(':not(:animated)').animate({'left' : leftPos}, 500, function() { $('li:last', $car).after($('li:first', $car)); $car.css({'left' : $offset}); }); $('li:eq(' + ( ctr_img + 1 ) + ')', $car).animate({ scale: '1' }, 500); $('li:eq(' + ctr_img + ')', $car).animate({ scale: '0.75' }, 500); }); |
Now we can start setting up our click events. First our right button. I’ll skip the click binding since that is the same as normal. Obviously you will need to change the path to your right (and left) buttons if you wish, but that is up to you.
The first line of our click event grabs the outer width of our list item. This is the width of the element plus any border, and/or padding. Adding the true boolean also adds in margin, which is perfect for us.
The next line figures out the new left position for the animation by taking the list item width away from the current left position. Since out left position is negative subtracting from it actually adds to it and pushes our left position further into the negative, moving our list items further left.
Now we check to see if our UL is being animated (to stop crazy clickers from causing problems) and animate it to our new left position. Feel free to customize the animation timing although I think 500ms is nice.
Next in a callback function called when our animation finishes we place the first image in our list at the end of the UL. I’ll explain more with the infographics later but suffice to say it basically creates the infinite carousel effect.
Finally we push the left position back to the original offset. We need to do this since we have removed an item from the front meaning our left position no longer needs to take that item into account. Luckily that makes our original position correct again so we can just use that.
As for these last two lines; The first scales up the right image to 100% as it moves into the center, while the second line scales down the previous center image to 75% as it moves out to the left. How do we find the next and center image? Well we just use the ctr_img
variable & jQuery’s :eq()
selector.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
$('#photos_left img').click(function(){ var itemWidth = $('li', $car).outerWidth(true); var leftPos = parseInt($car.css('left')) + itemWidth; $car.filter(':not(:animated)').animate({'left' : leftPos}, 500, function() { $('li:first', $car).before($('li:last', $car)); $car.css({'left' : $offset}); }); $('li:eq(' + ( ctr_img - 1 ) + ')', $car).animate({ scale: '1' }, 500); $('li:eq(' + ctr_img + ')', $car).animate({ scale: '0.75' }, 500); }); }); |
The code for the left button is nearly the same. The only differences are we add to our left position thereby decreasing our left position. We place the last image before the first one, then reset the left position. Finally we scale the previous image to 100% instead of our next image as we are rotating the carousel the opposite way.
Infinite Carousel Gallery: Infinite Concept Explanation
Now for those that want to understand how the whole infinite part of the carousel works here is a infographics style explanation.
Here you can see how the images are laid out. It shows that when the page is loaded the last two images are actually at the front of the carousel. There are 7 images because that’s how many I used in my original example, but to show that it works with any number the demo shown at the start of this tutorial actually has 13 images.
Pressing right will push all the images to the left. The next image to the right will become the center image & to make sure it will be infinite the first image is moved to the end of the list. Every time you press the right button this happens, hence why you never run out of images to view.
Pressing left will push all the images to the right. The next image to the left will become the center image & again to make sure it will be infinite the last image is moved to the front of the list. Once again it does this on every press of the left button. This creates the infinite effect in the opposite direction.
Infinite Carousel Gallery: Conclusion
It’s been a long tutorial, but that is finally it. Hopefully I’ve explained how this all works to a point where it isn’t confusing. I built it, but even I still have moments where it confuses me simply due to the Maths involved (which I was never very good at).
Please remember that this is a tech demo again. Really though other than the scaling & box shadows in Internet Explorer 8, and below there isn’t anything that should cause older browsers many problems.
As always let me know if you have any comments, suggests, questions, or you just wanna say hey this is cool. 🙂 It’s always nice to hear from you guys & gals.
71 Comments
Julia
Thanks for the great jQuery carousel. I have one idea for you. I need it too) When you click on right arrow auto sliding are rotating to right side, when you click on left arrow auto sliding are rotating to left side. By default, it rotates to the left side for example. It is difficult to do?
Sorry for my English. I am from Ukraine)
Paul Robinson
Hi Julia,
I’m sorry I’m not sure what you are asking?
Are you asking if it can be made into an auto slider? Someone a few comments back managed to get that working so you could check that out.
Dreau
[ed:- Thanks for sharing your alterations with us Dreau. A little bit of your code got stripped so I tried to put it back as best I could. Let me know if I’ve missed anything.]
Paul this is fantastic thank you!!
Just an add on if you want something extra. Change the onclick from img to ‘a’ so you can use the css a:hover for image change over the next and previous buttons. Just to let you know your over the button…
In the javascript…
Change the
to
of course you would do the same for
In the CSS…
add
do the same for the photos left.
and the HTML…
change the
to
.
Do the same for the photos right.
Now when you hover over the next or previous button the image will change.
Paul Robinson
Hi Dreau,
as I said in the little comment, thank you for sharing your changes. Let me know if I’ve guessed your code wrong as WP stripped a little bit of it.
Andrw
Nice work! thank you so much… this was a great help 😉
Paul Robinson
No problem. Glad it helped you out.
Eddie K
Great stuff right here. Very nice.
Slightly disappointed by the fact that the link leads to a static image. Was expecting it to blow into a lightbox or something similar.
I am thinking of hooking this up with lightbox so the use does not have to leave the page when they click on an image.
Any ideas?
Paul Robinson
Hi Eddie,
I actually wanted to put a lightbox on when I first created it, but ended up forgetting.
I’ve added a lightbox to the demo so you can see what it would look like. I can’t find my full versions of all of the images so I’ve added another one to the demo (the 7th image to the right) so you can see the full sized lightbox working.
It’s pretty simple to add one in, but it depends on what lightbox you are using. With most though, if not all, you’d just want to target
#photos_ul a
to trigger the lightbox script.Hope that helps, you can always view the source of the demo to see how I added the lightbox, if you have any questions please feel free to leave a comment, or drop me an email. 🙂
Eddie K
Thank you for the speedy response as regards the lightbox. I am busy shamelessly copying and pasting your labours 🙂
Quick question on your lightbox, is there any particular reason why the lightbox does not allow the user to move to the next image without jumping out of the lighbox?
Paul Robinson
Hi Eddie,
No problem. 😉
Other than the fact you could then go through all the images without using the carousel, nope, lol.
If you want to be able to do that though feel free, you only need to add a rel attribute into all of the image tags & that should get the gallery system working. 😉
britain
and jcarousel ,it’s possible ???
thank you
Paul Robinson
Hi,
I’m sorry. I’m not sure I know what you are asking?
richard
vertical it’s possible?
Paul Robinson
Hi Richard,
I don’t see why not, but you would have to alter the code to use the same premise but vertically. I would love to make it, but I just don’t have the spare time available. Sorry.
Henry
Hi Paul !
nice work.
How to add a caption below?
Thanks .)
Paul Robinson
Hi,
You could add the caption using the title attribute of the hyperlinks, or using the alt attribute of the image. Or even better, since this is HTML 5 you could use a
data-*
attribute to store it on the image.Then it would be a case of adding an element into the code to show the caption, then some extra jQuery to load & swap the caption when the buttons are clicked.
I’d love to help out as I’m intrigued to know if it would work & look good, but I’m afraid I’m really packed with work at the moment & just don’t have the time to code it. 🙁
Lexy
Love this plugin! Excellent work.. 🙂 I however have a question about the minimum amount of images allowed for this to work.. I assumed it was three, but apparently not. Is there any way to make this function correctly when there are only three images present? Right now, it scrolls infinitely perfectly, but it doesn’t resize the middle photo to full scale. Thank you!
Paul Robinson
Hi Lexy,
It should indeed work. Are you by any chance in a browser that doesn’t support CSS based scaling?
Indra
hi i found your website via google, and im interested with your infinite carousel photo gallery.
could you tell me how to change thebehavior of to go to the url, instead of open it in jquery lightbox??
thanks a lot
-Indra-