Image Comparison Slider

Image Comparison Slider

A handy draggable slider to quickly compare 2 images, powered by CSS3 and jQuery.

Nucleo icons

Sponsored by Nucleo, a free application to collect, customize and export all your icons as icon font and SVG symbols. Made by the CodyHouse folks!

Do you want to include this resource in a product offered for sale? Learn more about our Extended License

When you create a product page, there are some effective UX solutions that can be used to make the user 'feel' the product. A comparison image slider is one of those.  If you look at the Sony Ultra HD TV product page, they use this approach to emphasize the difference between their display resolution and a standard one. Google uses it to show how cool is a Google+ Photos filter.

Image credits: Unsplash.

Let's dive into the code ;)

Creating the structure

We used a figure element to wrap our original image, the modified image and the slider handle:

<figure class="cd-image-container">
   <img src="img/img-original.jpg" alt="Original Image">
   <span class="cd-image-label" data-type="original">Original</span>
  
   <div class="cd-resize-img"> <!-- the resizable image on top -->
      <img src="img/img-modified.jpg" alt="Modified Image">
      <span class="cd-image-label" data-type="modified">Modified</span>
   </div>
  
   <span class="cd-handle"></span> <!-- slider handle -->
</figure> <!-- cd-image-container -->

Adding style

The original image is used to give the correct dimentions to its container .cd-image-container; the modified image is inserted inside the div.cd-resize-image. This element is set in position: absolute over the .cd-image-container and its width is changed while dragging the .cd-handle element (using jQuery) in order to reveal/hide the modified image.
The .cd-resize-image width is originally set to 0, and then changed to 50% when it  enters the viewport, using the .is-visible class which is added to the .cd-image-container (using jQuery). We also defined the cd-bounce-in animation to create a bounce effect.
This way, the animation will only start when the .cd-image-container is visible inside the viewport.

.cd-resize-img {
  position: absolute;
  top: 0;
  left: 0;
  height: 100%;
  width: 0;
  overflow: hidden;
  /* Force Hardware Acceleration in WebKit */
  transform: translateZ(0);
  backface-visibility: hidden;
}
.is-visible .cd-resize-img {
  width: 50%;
  /* bounce in animation of the modified image */
  animation: cd-bounce-in 0.7s;
}
@keyframes cd-bounce-in {
  0% {
    width: 0;
  }
  60% {
    width: 55%;
  }
  100% {
    width: 50%;
  }
}

Events handling

To implement the slider functionality, we defined the drags() function to make the .cd-handle element draggable (credit to CSS-Tricks).
When the mouse is pressed over the .cd-handle element and moved, we update the .cd-handle left value according to the current mouse position (we have added a constrain to limit the movement inside its parent .cd-image-container) and change the div.cd-image-size width accordingly.

In order to add mobile support, we have been using jQuery mobile (specifically, the vmouse events which simulate the mouse events on a touch device).

As last effect, when the .cd-image-container element enters the viewport, we add the .is-visible class to animate its children.

jQuery(document).ready(function($){
   //function to check if the .cd-image-container is in the viewport here
   // ...
    
   //make the .cd-handle element draggable and modify .cd-resize-img width according to its position
   $('.cd-image-container').each(function(){
      var actual = $(this);
      drags(actual.find('.cd-handle'), actual.find('.cd-resize-img'), actual);
   });

   //function to upadate images label visibility here
   // ...
});

//draggable funtionality - credits to http://css-tricks.com/snippets/jquery/draggable-without-jquery-ui/
function drags(dragElement, resizeElement, container) {
   dragElement.on("mousedown vmousedown", function(e) {
      dragElement.addClass('draggable');
      resizeElement.addClass('resizable');

      var dragWidth = dragElement.outerWidth(),
          xPosition = dragElement.offset().left + dragWidth - e.pageX,
          containerOffset = container.offset().left,
          containerWidth = container.outerWidth(),
          minLeft = containerOffset + 10,
          maxLeft = containerOffset + containerWidth - dragWidth - 10;
        
      dragElement.parents().on("mousemove vmousemove", function(e) {
         leftValue = e.pageX + xPosition - dragWidth;
            
         //constrain the draggable element to move inside its container
         if(leftValue < minLeft ) {
            leftValue = minLeft;
         } else if ( leftValue > maxLeft) {
            leftValue = maxLeft;
         }

         widthValue = (leftValue + dragWidth/2 - containerOffset)*100/containerWidth+'%';

         $('.draggable').css('left', widthValue).on("mouseup vmouseup", function() {
            $(this).removeClass('draggable');
            resizeElement.removeClass('resizable');
         });

         $('.resizable').css('width', widthValue); 

         //function to upadate images label visibility here
         // ...

      }).on("mouseup vmouseup", function(e){
         dragElement.removeClass('draggable');
         resizeElement.removeClass('resizable');
      });
      e.preventDefault();
   }).on("mouseup vmouseup", function(e) {
      dragElement.removeClass('draggable');
      resizeElement.removeClass('resizable');
   });
})

Join our newsletter

Get our monthly recap with the latest CodyHouse news