Parallax Image Slider With jQuery And Swiper.js

File Size: 10.4 KB
Views Total: 4961
Last Update:
Publish Date:
Official Website: Go to website
License: MIT
   
Parallax Image Slider With jQuery And Swiper.js

This project makes use of jQuery and Swiper.js to create a modern, mobile-friendly, multi-slide carousel slider with a pretty parallax scrolling effect when transitioning between images.

How to use it:

1. Load the necessary jQuery and Swiper.js libraries in the document.

<link rel="stylesheet" href="/path/to/cdn/swiper.min.css" />
<script src="/path/to/cdn/jquery.min.js"></script>
<script src="/path/to/cdn/swiper.min.js"></script>

2. Add images to the slider.

<div class="multi-px-slider loading">

  <!-- Left Slider -->
  <div class="swiper-container lg-slider">
    <div class="swiper-wrapper">
      <div class="swiper-slide">
        <div class="mps-slide">
          <div class="mps-img img-lg"><img data-src="https://source.unsplash.com/TWCSYLJMoVc/1280x960" alt="" class="swiper-lazy object-fit"></div>
          <div class="swiper-lazy-preloader"></div>
        </div>
      </div>
      <div class="swiper-slide">
        <div class="mps-slide">
          <div class="mps-img img-lg"><img data-src="https://source.unsplash.com/yHaburAEFo4/1280x960" alt="" class="swiper-lazy object-fit"></div>
          <div class="swiper-lazy-preloader"></div>
        </div>
      </div>
      <div class="swiper-slide">
        <div class="mps-slide">
          <div class="mps-img img-lg"><img data-src="https://source.unsplash.com/ihzhMA2-l4Q/1280x960" alt="" class="swiper-lazy object-fit"></div>
          <div class="swiper-lazy-preloader"></div>
        </div>
      </div>
    </div>
    <div class="pattern-2" data-swiper-parallax="-50%"></div>
  </div>

  <!-- Right Slider -->
  <div class="swiper-container sm-slider">
    <div class="swiper-wrapper">
      <div class="swiper-slide">
        <div class="mps-slide">
          <div class="mps-img img-sm"><img data-src="https://source.unsplash.com/Dz5j0QKVUGY/1280x960" alt="" class="swiper-lazy object-fit"></div>
          <div class="swiper-lazy-preloader"></div>
        </div>
      </div>
      <div class="swiper-slide">
        <div class="mps-slide">
          <div class="mps-img img-sm"><img data-src="https://source.unsplash.com/HGa7kULkQWY/1280x960" alt="" class="swiper-lazy object-fit"></div>
          <div class="swiper-lazy-preloader"></div>
        </div>
      </div>
      <div class="swiper-slide">
        <div class="mps-slide">
          <div class="mps-img img-sm"><img data-src="https://source.unsplash.com/RRSXLJPbqEQ/1280x960" alt="" class="swiper-lazy object-fit"></div>
          <div class="swiper-lazy-preloader"></div>
        </div>
      </div>
    </div>
  </div>

  <!-- Controls -->
  <button type="button" class="mps-arrow mps-prev" aria-label="Previous">Previous</button>
  <button type="button" class="mps-arrow mps-next" aria-label="Next">Next</button>

  <!-- Curtain -->
  <div class="curtain"></div>

</div>

3. The necessary CSS for the slider..

.object-fit { 
  width: 100%; 
  height: 100%; 
  object-fit: cover; 
} 

/* plugin overrides */
.swiper-wrapper {
  height: 100%;     
}
.swiper-slide {
  backface-visibility: hidden;
  overflow: hidden;     
}


/* slider */
.multi-px-slider {
  height: 480px;
  position: relative;
  overflow: hidden;
  display: flex;
  transition: opacity .6s ease;
}

.multi-px-slider.loading {
  visibility: hidden;
  opacity: 0;
}

.mps-slide {
  position: relative;
  width: 100%;
  height: 100%;
}

.mps-img {
  height: 100%;
  overflow: hidden;
}

/* Large slider */
.lg-slider {
  width: 60%;
}

/* Small slider */
.sm-slider {
  width: 40%;
}

/* Arrows */
.mps-arrow {
  position: absolute;
  top: 50%;
  z-index: 3;
  transform: translateY(-50%);
}

.mps-prev {
  left: 1.5em;
}

.mps-next {
  right: 1.5em;
}

/* curtain */
.curtain {      
  position: absolute;
  top: 0;
  left: 60%;
  z-index: 2;
  width: 40%;
  height: 100%;
  background-color: rgba(0,0,0,.5);
}

.is-animating .curtain {
  animation: curtain 3.75s ease-in-out;
}

@keyframes curtain {
  0% {
    left: 60%;
    width: 40%;
  }
  46% {       
    left: 0%;
    width: 60%;
  }
  53% {
    left: 0%; 
    width: 60%;     
  }
  100% {        
    left: 60%;
    width: 40%;
  }
}

.pattern-2 {
  background: url(./images/pattern-2.png) repeat-x;
  width: 330%;
  height: 80px;
  position: absolute;
  bottom: 0;
  left: 0;
  z-index: 2;
  opacity: .3;    
}

4. Enable the parallax slider.

// Params
const mpSlider = document.querySelector('.multi-px-slider');
let interleaveOffset = 0.5;

// init small slider
const smallSlider = new Swiper('.sm-slider', {
      touchRatio: 0, // disable swipe
      loop: true,
      slidesPerView: 'auto',
      preloadImages: false,
      lazy: {
        loadPrevNext: true,
        loadPrevNextAmount: 2,
      },
      watchSlidesProgress: true,
      watchSlidesVisibility: true,
      on: {
        init: function(){
          let swiper = this;
        },
        lazyImageReady: function(){
          let swiper = this;

          setTimeout(function() {
            swiper.update();
          }, 500);
        },
        progress: function(){
          let swiper = this;
          for (let i = 0; i < swiper.slides.length; i++) {
            let slideProgress = swiper.slides[i].progress,
                innerOffset = swiper.width * interleaveOffset,
                innerTranslate = slideProgress * innerOffset;
                swiper.slides[i].querySelector(".img-sm").style.transform = "translateX(" + innerTranslate + "px)";
          }
        },
        touchStart: function() {
          let swiper = this;
          for (let i = 0; i < swiper.slides.length; i++) {
              swiper.slides[i].style.transition = "";
          }
        },
        setTransition: function(speed) {
          let swiper = this;
          for (let i = 0; i < swiper.slides.length; i++) {
              swiper.slides[i].style.transition = speed + "ms";
              swiper.slides[i].querySelector(".img-sm").style.transition = speed + "ms";
          }
        }
    }
});


// init large slider
const largeSlider = new Swiper('.lg-slider', {
  parallax: true,
    loop: true,
    speed: 2000,
    slidesPerView: 'auto',
    preloadImages: false,
    lazy: {
      loadPrevNext: true,
      loadPrevNextAmount: 2,
    },
    watchSlidesProgress: true,
    watchSlidesVisibility: true,
    touchEventsTarget: 'wrapper',
    controller: {
      control: smallSlider
    },
    on: {
      init: function(){
        let swiper = this;
      },
      lazyImageReady: function(){
        let swiper = this;

        setTimeout(function() {
          swiper.update();
          mpSlider.classList.remove('loading');
        }, 500);
      },
      progress: function(){
        let swiper = this;
        for (let i = 0; i < swiper.slides.length; i++) {
          let slideProgress = swiper.slides[i].progress,
              innerOffset = swiper.width * interleaveOffset,
              innerTranslate = slideProgress * innerOffset;
              swiper.slides[i].querySelector(".img-lg").style.transform = "translateX(" + innerTranslate + "px)";
        }
      },
      touchStart: function() {
        let swiper = this;
        for (let i = 0; i < swiper.slides.length; i++) {
            swiper.slides[i].style.transition = "";
        }
      },
      setTransition: function(speed) {
        let swiper = this;
        for (let i = 0; i < swiper.slides.length; i++) {
            swiper.slides[i].style.transition = speed + "ms";
            swiper.slides[i].querySelector(".img-lg").style.transition = speed + "ms";
        }
      }
    }
});


// Set up animations
let slideDelay = 2000;
let $mpsArrow = $('.mps-arrow');

function runAnimation() {
  mpSlider.classList.add('is-animating');
}

function endAnimation() {
  mpSlider.classList.remove('is-animating');
}


// custom arrows
$mpsArrow.each((i, el) => {
const _this = $(el);

  _this.on('click', function() {

    // disable arrows
    $mpsArrow.prop('disabled', true);
    // run animation
    runAnimation();

    // go to prev/next slide
    if (_this.hasClass('mps-prev')) {
      setTimeout(() => {
      largeSlider.slidePrev();
      }, slideDelay)
    } else if (_this.hasClass('mps-next')) {
      setTimeout(() => {
      largeSlider.slideNext();
      }, slideDelay)
    }

    // detect animation end
    const curtain = document.querySelector('.curtain');
    curtain.addEventListener('animationend', () => {
      // re-enable arrows
    $mpsArrow.prop('disabled', false);
    // end animation
    endAnimation();
    });

  })

})

// check if slider is in viewport?
let mpsInViewport = true;
if (mpsInViewport) {
  $(document).off('keyup').on('keyup', function(e) {
    if (e.keyCode == '37') {
      $('.mps-prev').trigger('click');
    } else if (e.keyCode == '39') {
      $('.mps-next').trigger('click');
    }
  });
}

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