Search code examples
javascriptjqueryhtmlcssslideshow

Explanation for basic JavaScript slideshow


I am using JQuery to create a custom slideshow-layout and I am working on code that will

  1. Calculate the width of the screen
  2. Subtract the width of the images
  3. Set the left margin to 1/3 of the difference between the width of the screen and images

The images seem to line up but chop off for the last of the 3 images. I am trying to make this dynamic so that it will make a spaced-out layout for any amount of images. Am I going about this all wrong? Also, is the space between inline-block elements setting it off?

var sl = $('.slideIt')
var acc = 0
for (var i = 0; i < $('.slideIt img').length; i++) {
  acc += $('.slideIt').eq(i).width();
}
var distanceRatio = ($(window).innerWidth() - acc) / sl.children().length;

$('.slideIt').css('marginLeft', '' + distanceRatio + 'px')
.imageSlideHolder {
  margin: 0 auto;
  width: 100%;
  overflow: hidden;
  position: relative;
}

.slideIt {
  display: inline-block;
  position: relative;
  width: 33%;
}

.slideIt img {
  position: relative;
  width: 100%;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<h1>Image Slideshow</h1>

<div class='imageSlideHolder'>
  <div class='slideIt'>
    <img src='im1.jpg' />
  </div>
  <div class='slideIt'>
    <img src='im2.jpg' />
  </div>
  <div class='slideIt'>
    <img src='im3.jpg' />
  </div>
</div>


Solution

  • You don't have to calculate the width of anything. By using CSS you can layout the items in a row with Flexbox. Wrap all your slides inside another element, in this example we call this element imageSlideRails, that moves all the slides together instead of moving them individually.

    I would recommend using the CSS transform property instead of margin to make the slider move. This will increase performance and prevent unwanted behaviors, like elements pushing each other away.

    The amount that you slide can be the same value as the flex-basis value on a slide. Let's say a slide is 33.3%. If you move the rails to -33.3%, then the first slide will move out of view and the next slide will come into view. This way the calculation will always be precise.

    Checkout the snippet below.

    var index = 1;
    var slideWidth = 33.3;
    var slidesLength = $('.slideIt').length;
    var $rails = $('.imageSlideRails');
    
    setInterval(function() {
      $rails.css('transform', `translate3d(${index * -slideWidth}%, 0, 0)`);
      if (index === slidesLength - 1) {
        index = 0;
      } else {
        index++;
      }
    }, 2000);
    .imageSlideHolder {
      margin: 0 auto;
      width: 100%;
      overflow: hidden;
      position: relative;
    }
    
    .imageSlideRails {
      display: flex;
      flex-flow: row nowrap;
      transition: transform 1s ease-in-out;
    }
    
    .slideIt {
      box-sizing: border-box;
      position: relative;
      width: 33.3%;
      flex-grow: 0;
      flex-shrink: 0;
      flex-basis: 33.3%;
      padding: 15px;
      overflow: hidden;
    }
    
    .slideIt img {
      position: relative;
      width: 100%;
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
    <h1>Image Slideshow</h1>
    
    <div class='imageSlideHolder'>
      <div class="imageSlideRails">
        <div class='slideIt'>
          <img src='https://www.fillmurray.com/640/360' />
        </div>
        <div class='slideIt'>
          <img src='https://www.fillmurray.com/640/360' />
        </div>
        <div class='slideIt'>
          <img src='https://www.fillmurray.com/640/360' />
        </div>
        <div class='slideIt'>
          <img src='https://www.fillmurray.com/640/360' />
        </div>
        <div class='slideIt'>
          <img src='https://www.fillmurray.com/640/360' />
        </div>
      </div>
    </div>