Responsive Horizontal Image Slider with jQuery and CSS3

File Size: 4.19 KB
Views Total: 11523
Last Update:
Publish Date:
Official Website: Go to website
License: MIT
   
Responsive Horizontal Image Slider with jQuery and CSS3

A jQuery responsive image slider plugin which allows to move a set of images right of left using the mouse, trackpad, keyboard or touch.

Features:

  • The number of images across changes with browser width. The scroll speed changes as well; faster as width get smaller.
  • Left and right scroll buttons always animate to the next set of images. You'll never have a cut-off image unless the user manually scrolls. If an image is cut-off, it'll be fully visible on the next set.
  • Get an enlarged view of an image without leaving the scroller. Image resets when scrolling with buttons.

How to se it:

1. Add a set of images with next/prev navigation to the horizontal slider. In this example, we use Font Awesome 4 for navigation icons.

<div id="scroll-feature" class="horiz-scroll">
  <div class="scroller">
    <div class="left-scroll invisible">
      <p class="fa fa-angle-left"></p>
    </div>
    <div class="right-scroll">
      <p class="fa fa-angle-right"></p>
    </div>
    <div class="scroll-images scrollable-x">
      <img src="1.jpg" alt="Image 1">
      <img src="2.jpg" alt="Image 2">
      <img src="3.jpg" alt="Image 2">
      ...
    </div>
  </div>
</div>

2. The primary slider styles.

.horiz-scroll {
  display: flex;
  display: -webkit-flex;
  flex-direction: column;
  -webkit-flex-direction: column;
  overflow: visible;
  position: relative;
}

.horiz-scroll h2 { font-weight: 600; }

.horiz-scroll .scroller {
  max-height: 30vw;
  position: relative;
  display: flex;
  display: -webkit-flex;
  flex: 1;
  -webkit-flex: 1;
  background-color: white;
}

.horiz-scroll .scroller .left-scroll { left: 0; }

.horiz-scroll .scroller .right-scroll { right: 0; }

.horiz-scroll .scroller .left-scroll, .horiz-scroll .scroller .right-scroll {
  display: flex;
  display: -webkit-flex;
  flex-direction: column;
  -webkit-flex-direction: column;
  padding: 0 2vw;
  overflow-x: hidden;
  z-index: 1;
  justify-content: center;
  -webkit-justify-content: center;
  position: absolute;
  height: 100%;
}

.horiz-scroll .scroller .left-scroll p, .horiz-scroll .scroller .right-scroll p {
  font-size: 3em;
  color: white;
  text-shadow: 0 0 10px #333;
  margin: 0;
}

.horiz-scroll .scroller .scrollable-x {
  white-space: nowrap;
  overflow-x: scroll;
  overflow-y: hidden;
}

.horiz-scroll .scroller .scrollable-x::-webkit-scrollbar {
  display: none;
}

.horiz-scroll .scroller .scrollable-x::-webkit-scrollbar {
 width: .375em;
 max-width: 12px;
}

.horiz-scroll .scroller .scrollable-x::-webkit-scrollbar-track {
   background-color: transparent;
}

.horiz-scroll .scroller .scrollable-x::-webkit-scrollbar-thumb {
  background-color: rgba(255, 255, 255, 0.25);
  border-radius: 1em;
}

.horiz-scroll .scroller .scroll-images {
  position: relative;
  flex: 8;
  -webkit-flex: 8;
  order: 2;
  -webkit-order: 2;
  z-index: 0;
  font-size: 0;
  overflow-y: visible;
  padding: 10% 0;
  margin: -10% 0;
  text-align: center;
}

.horiz-scroll .scroller .scroll-images img {
  width: 25%;
  top: 0;
  z-index: 0;
  -webkit-transition: all 100ms;
  transition: all 100ms;
  position: relative;
}

.horiz-scroll .scroller .scroll-images img.focused {
  z-index: 2;
  box-shadow: 0 5px 10px rgba(0, 0, 0, 0.25);
  transform: scale(1.25);
  height: 200%;
  transition: all 250ms ease-in-out, drop-shadow 0.5s;
}

.invisible {
  opacity: 0;
  transition: .5s ease-in-out;
}

3. Make it responsive.

@media only screen and (max-width: 480px) {

.horiz-scroll .scroller .left-scroll p,  .horiz-scroll .scroller .right-scroll p { color: black; }

}

@media only screen and (max-width: 960px) {

.horiz-scroll .scroller .scroll-images img { width: 33.333%; }

}

@media only screen and (max-width: 720px) {

.horiz-scroll .scroller .scroll-images img { width: 50%; }

}

@media only screen and (max-width: 480px) {

.horiz-scroll .scroller .scroll-images img {
  width: 50%;
  margin: 0 25%;
}

}

4. Put jQuery JavaScript library at the bottom of the web page.

<script src="//code.jquery.com/jquery-2.1.4.min.js"></script> 

5. The core JavaScript (jQuery script).

// The HorizontalScroller Class accepts a jQuery object as its only argument
// The argument is the parent container of the scrolling element
// The element requires an ID to differentiate HorizontalScroller instances

function HorizontalScroller(elem) {
  this.scrollbox = elem; // The scrollers viewable area
  this.scrollImages = this.scrollbox.find("img");
  this.leftScrollControl = this.scrollbox.siblings(".left-scroll");
  this.rightScrollControl = this.scrollbox.siblings(".right-scroll");

  // Listener to change visibility of left and right controls
  // when at scroll extremes
  this.scrollbox.on("scroll", this.evaluateControlVisibility.bind(this));
};

HorizontalScroller.prototype = {
  
  scrollboxWidth: function() {
    return this.scrollbox.outerWidth(true);
  }, 

  currentScrollPosition: function() {
    return this.scrollbox.scrollLeft();
  },

  currentRightPosition: function() {
    return this.currentScrollPosition() + this.scrollboxWidth() - this.totalWidths();
  },

  // Maps the image width of each image in the scroller
  imageWidths: function() {
    return $.map(this.scrollImages, function(img) { 
      return $(img).outerWidth(true);
    })
  },

  // Returns the total width of all the images, that is,
  // the total of the visible and overflow content.
  totalWidths: function() {
    return this.imageWidths().reduce(function(a,b) { return a+b});
  },

  // Returns the average width of all the images
  avgWidth: function() {
    return this.totalWidths() / this.imageWidths().length;
  },

  // Determines the number of images in view area.
  // Number of images changes with responsive CSS
  imagesAcross: function() {
    return Math.round( this.scrollboxWidth() / this.avgWidth() );
  },

  // maps the offset x-distance of each image
  // from the left edge of the view area
  imageOffsets: function() {
    return $.map(this.scrollImages, function(img) { 
      return Math.round($(img).position().left);
    }); 
  },

  // Returns the index of the first number in the given array
  // greater than the given value, or, returns the index of
  // the first positive number in the array
  indexOfFirst: function(array, value) {
    value = value || 0;
    var firstIndex;
    var i = 0;
    while (firstIndex === undefined && array.length > i) {
      if (array[i] >= value)
        firstIndex = i; 
      i += 1;
    }
    return firstIndex; 
  },

  // Returns the index of first image that is completely in view
  // within the scrollbox
  firstVisibleImageIndex: function() {
    return this.indexOfFirst(this.imageOffsets());
  },

  // Returns the first image that is completely in view 
  // within the scrollbox
  firstVisibleImage: function() {
    return this.scrollImages[this.firstVisibleImageIndex()];
  },

  // Returns the index of the last image with its left edge in view 
  // within the scrollbox
  lastVisibleImageIndex: function() {
    return this.firstVisibleImageIndex() + this.imagesAcross();
  },

  // Returns the last image with its left edge in view 
  // within the scrollbox
  lastVisibleImage: function() {
    return this.scrollImages[this.lastVisibleImageIndex()];
  },

  // Returns the difference between the scrollboxes left edge
  // and the left edge of the first fully visible image, that is,
  // how far in the first fully visible image is
  offset: function() {
    var offset = $(this.firstVisibleImage()).position().left;
    return Math.round(offset);
  },
  
  // Returns the combined scroll amount that the images have to travel
  // in order to land evenly within the scroll window. The resulting
  nextScrollPosition: function(direction) {
    var nextScrollPosition = this.currentScrollPosition() + this.offset();

    switch(direction) {
      case "left":
        nextScrollPosition -= this.scrollboxWidth();
        if (($(this.firstVisibleImage()).outerWidth(true) - this.offset()) < 0) {
          nextScrollPosition -= $(this.firstVisibleImage()).outerWidth(true);
        }
        break;
      case "right":
        nextScrollPosition += this.scrollboxWidth();
        if (this.offset() > 0) {
          nextScrollPosition -= $(this.firstVisibleImage()).outerWidth(true);
        }
        break;
    }
    return nextScrollPosition;
  },

  // Triggers the animation
  animateScroll: function(direction) {
    resetFocusedImg();
    var scroller = this;
    setTimeout(function() {
      scroller.scrollbox.animate({
        scrollLeft: scroller.nextScrollPosition(direction)
      }, this.scrollboxWidth())
    }.bind(this), 100);
  },

  hideScrollControl: function(control) {
    control.addClass("invisible");
  },

  showScrollControl: function(control) {
    control.removeClass("invisible");
  },

  scrollControlVisibility: function(control) {
    return control.hasClass("invisible");
  },
  
  scrollAtZero: function() {
    return this.currentScrollPosition() == 0;
  },

  scrollAtMax: function() {
    return this.currentRightPosition() >= -1;
  },

  evaluateControlVisibility: function() {
    var left = this.leftScrollControl;
    var right = this.rightScrollControl;
    var leftIsInvisible = this.scrollControlVisibility(left);
    var rightIsInvisible = this.scrollControlVisibility(right);

    if (this.scrollAtZero()) this.hideScrollControl(left);
    if (this.scrollAtMax()) this.hideScrollControl(right);
    if (!this.scrollAtZero() && leftIsInvisible) this.showScrollControl(left);
    if (!this.scrollAtMax() && rightIsInvisible) this.showScrollControl(right);
  }
};

// End HorizontalScroller.prototype

var scrollers = {};

// Detects scrollers in the DOM
function detectScrollers() {
  return $.map($(".horiz-scroll"), function(scroller) {
    return $(scroller).attr("id");
  });
}

// Generates a new HorizontalScroller for each scroller in DOM
function mapScrollers(scrollerIds) {
  scrollerIds.forEach(function(elem, i , arr) {
    var scroller = "#" + elem + " .scroll-images";
    scrollers[elem] = new HorizontalScroller( $(scroller) );
  });
}

// Gets the scroll direction to pass to animation function
function getScrollDirection(button) {
  return (button.hasClass("left-scroll")) ? "left" : "right"
}

// Triggers the scroll animation for specific scroller
// in a specific direction
function triggerAnimation(button) {
  var scrollId = button.closest(".horiz-scroll").attr("id");
  var scrollDirection = getScrollDirection(button);
  scrollers[scrollId].animateScroll(scrollDirection);
}

// Scroll buttons listener
function listenForScroll() {
  $(".left-scroll, .right-scroll").on("click", function() {
    var button = $(this);
    triggerAnimation(button);
  });
}

function resetFocusedImg() {
  $(".focused").removeClass("focused");
}

// listener for click, slides up
var horizontalScrollImg = $(".horiz-scroll .scroll-images img");
horizontalScrollImg.on("click", function() {
  if (!$(this).hasClass("focused"))
    resetFocusedImg();
  $(this).toggleClass("focused");
});

// Registers scrollers and initiates listeners 
function scrollerInit() {
  var scrollerIds = detectScrollers();
  mapScrollers(scrollerIds);
  listenForScroll();
}

6. Active the slider.

scrollerInit();

This awesome jQuery plugin is developed by hippolips. For more Advanced Usages, please check the demo page or visit the official website.