Changing images in a loop on hover using jQuery

Why use this Function?

Changing images in a loop on mouse over is a very common functionality that you’ll often find on e-commerce websites or portfolio websites. As an example, on the product list page, when you mouse over any product thumbnail, all the other images associated with that product start showing on top of the thumbnail after a specific interval. Many websites only have 2 images looping, which can be easily achieved via CSS only. But when there are more than 2 images to loop, you’ll need the help of a client side library. In this post, we’ll learn how to start the image loop on mouse over and then stop and reset the first image again on mouse out.

HTML Markup

To get started, create a couple of div elements which contain the images. Each div element will contain a set of images and image rotation will be controlled from within this set. All the images have “preview” as the CSS class. It’s a dummy CSS class that doesn’t have any styling, but it will be used in the jQuery code as a CSS selector to select the images. The images used for this post are from the FreeImages website.

<div class="list">
   <img src="http://images.freeimages.com/images/previews/dbb/shirt-1-1457400.jpg" class="preview" />
   <img src="http://images.freeimages.com/images/previews/025/shirt-2-1457399.jpg" class="preview" />
   <img src="http://images.freeimages.com/images/previews/2d6/shirt-3-1457403.jpg" class="preview" />
</div>
<div class="list">
   <img src="http://images.freeimages.com/images/previews/624/in-the-garden-1-1378570.jpg" class="preview" />
   <img src="http://images.freeimages.com/images/previews/7da/in-the-garden-2-1378564.jpg" class="preview" />
   <img src="http://images.freeimages.com/images/previews/9b6/in-the-garden-3-1378559.jpg" class="preview" />
   <img src="http://images.freeimages.com/images/previews/373/in-the-garden-4-1378553.jpg" class="preview" />
</div>

CSS

The following is the only CSS class used to set the width and height of all the images:

img {
  width: 300px;
  height: 300px;
}

jQuery Code

To implement this functionality, we will need to use JavaScript setInterval() and clearInterval(). The setInterval() method calls a function or evaluates an expression at specified intervals (in milliseconds). The setInterval() method will continue calling the function until clearInterval() is called, or the window is closed. The clearInterval() method clears a timer set with the setInterval() method. The basic idea is to iterate through each image from a set of grouped images, then control the visibility of the images.

The following is the outline of the jQuery solution:

  • Define a global variable myInterval which will be responsible for handling the setInterval() and clearInterval() This variable holds the reference of setInterval and is used by clearInterval to stop the setInterval function calls:

var myInterval = false;

  • When the page loads, we only want the first image to be visible so first hide all the images. We use CSS class selector to hide all the images:

$(".preview").hide();

  • Now all the images are hidden, but we need to display the very first image from each list. First, set the height of the DIV element to match the first images height. This is important as when images are shown on top of each other, the height of each image must match. To implement this, loop through all the DIV elements with list CSS class.
$("div.list").each(function() {
    $(".preview:first", this).show();
    $(this).height($(".preview:first", this).height());
});
  • Next, we need to attach the hover event to all images. To do this, make use of the CSS class selector and attach the hover event to preview CSS class. In this event, we make use of the setInterval() method to change/swap the images after a specific interval. But before we get to the setInterval part, we need to define variables for storing different values which will be used by setInterval() and clearInterval(). Take a look at the code below.
var $imgGrp = $(e.target);
var $parent = $imgGrp.parent(); // To get the parent element of image.
var $firstImage = $parent.children('.preview:first'); //Get first image
var iOffSet = $firstImage.offset(); // Get offset value of first image.

In this code, there are 4 variables defined:

  • The $imgGrp variable holds the current image reference.
  • The $parent variable holds the parent object of the current image.
  • The $firstImage variable holds the object of the very first image from the group of images.
  • The iOffSet variable stores the offset details of the first image using the jQuery .offset() This method allows us to retrieve the current position of an element relative to the document. Setting the top and left position of the first image to all subsequent images will ensure that images appear on top of each other.
  • Now, we define a function which will be called by the setInterval() method and store its reference in the myInterval variable which is defined globally. In the function, first define a variable called $nextImg. This variable will be used to hold the reference for the next image in the list of images. We also need to hide the first image. This is absolutely necessary, otherwise when the image changes there would be a brief moment when the first image would be visible, and the end product would appear sloppy.
var $nextImg;
$firstImage.hide();
  • The two variables $imgGrp and $nextImg are used to hold the reference of the current image and the next image. At the end of the function we assign the $nextImg variable to $imgGrp and then check if the currently displayed image is the last image. If the last image is displayed, then the next step would be to show the first image again to complete the loop. Therefore, we set $nextImg and $imgGrp variables to $firstImage and fade out the currently displayed image. If the last image is not displayed, get the next image from the group and store it in $nextImg
if ($imgGrp.next('.preview').length == 0) {
    $imgGrp.fadeOut('normal');
    $imgGrp = $firstImage;
    $nextImg = $imgGrp;
} else
    $nextImg = $imgGrp.next('.preview');
  • The $nextImg variable already holds the reference of the next image that needs to be shown. So set the top, left and position CSS properties for the next image to match with the first image position. The first image offset values are already stored in the iOffSet Use the same values to set this images top and left positions. Then, display the next image using the fadeIn() method and assign the $nextImg variable to $imgGrp.
If($imgGrp != $nextImg)
  $imgGrp.fadeOut('normal');
$nextImg.css({
    'top': iOffSet.top,
    'left': iOffSet.left,
    'position': 'absolute'
});
$nextImg.fadeIn('normal');
$imgGrp = $nextImg;

Here is the complete code of the setInterval function. The interval is set to 750 milliseconds, denoting the length of time between each image change (while the mouse is still hovering over the image).

myInterval = setInterval(function() {
    var $nextImg;
    $firstImage.hide();
    if ($imgGrp.next('.preview').length == 0) {
        $imgGrp.fadeOut('normal');
        $imgGrp = $firstImage;
        $nextImg = $imgGrp;
    } else
        $nextImg = $imgGrp.next('.preview');

    if ($imgGrp != $nextImg)
        $imgGrp.fadeOut('normal');
    $nextImg.css({
        'top': iOffSet.top,
        'left': iOffSet.left,
        'position': 'absolute'
    });
    $nextImg.fadeIn('normal');
    $imgGrp = $nextImg;
}, 750);
  • Now, we still need to look at the mouse out event. We’ll need to stop the image loop and then set the first image as the default image. We will also need to clear the reference of the setInterval() variable using clearInterval(). Here, one thing to take care of is disabling the fadeOut() method if the target image is the first image only. If we don’t disable this feature the first image will fade out and then fade in again, which doesn’t look good on UI. This is done via comparing the src attribute of the current image and the first image. The fadeOut() call is only made when they are not equal.
function() {
    var $imgGrp = $(this);
    var $parent = $imgGrp.parent();
    var $firstImage = $parent.children('.preview:first');
    if ($(this).attr('src') != $firstImage.attr('src')) {
        $(this).fadeOut('fast');
    }

    $firstImage.fadeIn('fast');
    clearInterval(myInterval);
    myInterval = false;
});

Finally, here is the complete jQuery code:

$(document).ready(function() {
    var myInterval = false;
    $(".preview").hide();
    $("div.list").each(function() {
        $(".preview:first", this).show();
        $(this).height($(".preview:first", this).height());
    });
    $('.preview').hover(function(e) {
            var $imgGrp = $(e.target);
            var $parent = $imgGrp.parent();
            var $firstImage = $parent.children('.preview:first');
            var iOffSet = $firstImage.offset();
            myInterval = setInterval(function() {
                var $nextImg;
                $firstImage.hide();
                if ($imgGrp.next('.preview').length == 0) {
                    $imgGrp.fadeOut('normal');
                    $imgGrp = $firstImage;
                    $nextImg = $imgGrp;
                } else
                    $nextImg = $imgGrp.next('.preview');
                if ($imgGrp != $nextImg)
                    $imgGrp.fadeOut('normal');
                $nextImg.css({
                    'top': iOffSet.top,
                    'left': iOffSet.left,
                    'position': 'absolute'
                });
                $nextImg.fadeIn('normal');
                $imgGrp = $nextImg;
            }, 750);
        },

        function() {
            var $imgGrp = $(this);
            var $parent = $imgGrp.parent();
            var $firstImage = $parent.children('.preview:first');
            if ($(this).attr('src') != $firstImage.attr('src')) {
                $(this).fadeOut('fast');
            }
            $firstImage.fadeIn('fast');
            clearInterval(myInterval);
            myInterval = false;
        });
});

You can also check out the demo at the following link!

This jQuery solution on mouse out restores the very first image on mouse out. If you don’t want this behavior to occur and would prefer to have the loop continue from the same image where the user left off, then you need to make the following changes to the code above:

  • In the $('.preview').hover function, get the offset of the current image instead of the first image. So change the following line,

var iOffSet = $firstImage.offset();
to,
var iOffSet = $imgGrp.offset();

  • In the second handler of the hover event, we only require code for clearing the interval. The rest of the code is not required as that part of the code sets the first image on mouse out. So the second handler code should look like this:
function() {
    clearInterval(myInterval);
    myInterval = false;
});

You can also check out the demo at the following link!

Conclusion

To sum it up, we saw the jQuery solution for creating a slideshow of images on mouse over. This continuous loop is stopped when the mouse is moved out of the image. The solution also offers 2 ways to handle mouse out. Either set the first image as the default image once again or continue from the current image. This feature adds a cool animation on the images thumbnail and is suitable for e-commerce websites or portfolio websites to showcase products. Since this is plain jQuery code, you can easily modify and change it as per your needs.



Responsive Menu
Add more content here...