Contact







09/03/2016

Infinite Carousel

How to create an infinite carousel using jQuery


I love my vanilla JavaScript, but sometimes jQuery allows you to do something so simply that it’s worth a little extra load time to save on the code time. Animation is one thing that jQuery does very well and although CSS3 animation is very useful, for the purpose of creating a carousel I still haven’t found an easier way than the method detailed below.



Concept



We want a window that will allow us to scroll left and right and view various elements. These elements will be divs and could contain text, images or whatever you choose to put them. We want the carousel to loop around so that we can continue scrolling indefinitely.

The way we will do this is to have a window div with overflow hidden. Inside of it we will have a div which we will call a card-holder that is set to a massive width, in this example 2000px, which will hold all the cards. The cards will also be divs and set to the same width and height of the main window and floated left so they line up horizontally in order. Due to the overflow being hidden, only the first card will be visible initially, but we will provide left and right buttons to scroll to different cards. We will use jQuery to animate the transition between cards. While the cards are off screen, we will manipulate their order to allow the infinite scrolling.

The following codePen has the complete code and demo. To fully understand how this works, click the 'edit on codePen' button and comment out the 'overflow: hidden' under the .window CSS.



See the Pen LyWBmP by Matthew Poulter (@Sectarian) on CodePen.



Let's go through the code.



HTML



The html is fairly simple, we have a number of divs: a Window, a card-holder, cards and a couple of buttons. The window is the parent div, with the card holder and buttons inside of it. The buttons are below the card-holder so they show on top of it when absolutely positioned. The cards, of which you can have as many as you like, then sit within the card-holder. We also have some button covers which will be explained a little later on. See the codePen for the classes.



CSS



View the codePen to see the full CSS but the important things are as follows:
- Window needs to be positioned relatively and have overflow hidden. You can set the width and height however you like.
- Card holder needs to be positioned relatively and be wide enough to accommodate all the cards. You need to set this to a high percentage, I've gone for 2000% which will fit 20 cards (important, see below).
- Cards need to be floated left and have 100% height and their width needs to calculated as 100% divided by the number of cards that can fit in the card-holder (in the demo it is 20). This will ensure that the carousel remains responsive in design.
- Buttons can be done however you like, but I have absolutely positioned them over the left and right edges of the window. The button covers, which we will come to later, need to have the same properties as the buttons, no matter how you design them.

At this point you should just be able to see a box with the first card in it and the buttons.


jQuery



With all the set up complete, It’s time to add some animation. We’ll focus on the slide-left action first. What we want to happen when we click the left button is for the card-holder to move left by the width of 1 card, thus making the second card visible in the window. We also want this to be animated. This can be a little tricky, so refer to the codePen above if you get stuck.

First of all, we create an event listener for the left button which is triggers a function when the button is clicked:



$('.lb').click(function(){

});


In this function we then want to create a variable to get the width of the card divs at the moment the button is clicked:



$('.lb').click(function(){
  var cardWidth = $('.card').width();
});


We then want to move the card-holder to the left by the amount stored in the variable we just created. We want to animate it and we also need to do some extra stuff when the animation is finished so we need a callback function. Fortunately, jQuery’s .animate() function has the capability to do all of this. So now our code looks like this:



$('.lb').click(function(){
   var cardWidth = $('.card').width();
   $('.card-holder').animate({left: ("-=" + cardWidth)}, 300, function(){
   });
});


Once the animation is complete, we want to remove the card that has just been moved out of shot to the left and place it at the far right of the card holder. To do this we create another variable and store the first card in it. We then use jQuery’s .remove() function to remove the first card. Because the cards are floated left, they will all naturally jump one space to the left so card 3 will become visible in the window. To solve this, we reset the card-holders ‘left’ property to zero, but without the animation so it is instant. This then puts the second card back into view in the window. This all happens so fast that it just looks like a smooth transition. The last thing we need to do is add the removed card to the right of all the other cards. We do this using jQuery’s .append() function and the variable we created at the start of the callback function. Our completed code looks like this:



$('.lb').click(function(){
   var cardWidth = $('.card').width();
   $('.card-holder').animate({left: ("-=" + cardWidth)}, 300, function(){
     var cardToBeRemoved = $('.card')[0];
     cardToBeRemoved.remove();
     $('.card-holder').css({left: 0});
     $('.card-holder').append(cardToBeRemoved);
  });
});


We now need to do the same thing for the right hand button but in reverse. So we want the bring the card that is furthest right in the holder to the left of the current card in the window, shift the card-holder left by one card width, then animate the new card coming in from the left. Again, this can be a little confusing so reference the codePen to get an idea of what is happening.

The good thing about the second function is that because the animation is the last thing that happens, we don’t need have a callback function. We do have to work out which is the last card in the card holder though and then get the index. That is simply done by getting the length of the card class and subtracting one.



$('.rb').click(function(){
   var cardWidth = $('.card').width();
   var cardCount = $('.card').length;
   var cardToAdd = $('.card')[cardCount - 1];
   cardToAdd.remove();
})


Finally we prepend the card we have just removed from the end using the jQuery .prepend() function and the variable we created, shift the cardholder left then animate it back to the right again to get this:



$('.rb').click(function(){
   var cardWidth = $('.card').width();
   var cardCount = $('.card').length;
   var cardToAdd = $('.card')[cardCount - 1];
   cardToAdd.remove();
   $('.card-holder').prepend(cardToAdd);
   $('.card-holder').css({left: -cardWidth});
   $('.card-holder').animate({left: ("+=" + cardWidth)}, 300);
});


Tidying Up



After testing there is a small issue we need to address.

Firstly, due to the way the animations work within jQuery, if you spam the right button, the cards move right before the animation completes and you end up messing up the carousel. Now we could remove the event listener on the button when it is clicked and then re-add it in a callback function for the animation, but there is a simpler way than messing with event listeners. Instead, we've created a button cover with the same properties as the right button but with its opacity set to zero and its display set to none. When the button is clicked, we use jQuery's .show() function to display the cover and prevent the button from being clicked, but the cover is completely invisible due to it's opacity. We then hide it again in the callback of the animation to allow the user to press the button again. This addition leaves the right button function looking like this:



$('.rb').click(function(){
   $('.buttonCover').show();
   var cardWidth = $('.card').width();
   var cardCount = $('.card').length;
   var cardToAdd = $('.card')[cardCount - 1];
   cardToAdd.remove();
   $('.card-holder').prepend(cardToAdd);
   $('.card-holder').css({left: -cardWidth});
   $('.card-holder').animate({left: ("+=" + cardWidth)}, 300, function(){
     $('.buttonCover').hide();
   });
});


The left button allows you to spam it without messing up the carousel, but there is a delay so once the user stops clicking, the carousel continues to move. We want it to have the same behaviour as the right button, so amend the left button function like so:



$('.lb').click(function(){
   $('.buttonCover').show();
   var cardWidth = $('.card').width();
   $('.card-holder').animate({left: ("-=" + cardWidth)}, 300, function(){
     var cardToBeRemoved = $('.card')[0];
     $('.card')[0].remove();
     $('.card-holder').css({left: 0});
     $('.card-holder').append(cardToBeRemoved);
     $('.buttonCover').hide();
   });
});


This is just one solution for the ever popular carousel in use on modern web pages. There may be better ways to do this, there may be simpler ways to do this, but I thoroughly enjoyed coming up with this solution and haven't had any issue with it so far. Feel free to use it and if you like it, please share this post below.