Stacked Card Slider With JavaScript – MVP Carousel

Category: Javascript , Slider | May 3, 2024
Author:pirolab
Views Total:247 views
Official Page:Go to website
Last Update:May 3, 2024
License:MIT

Preview:

Stacked Card Slider With JavaScript – MVP Carousel

Description:

This is a tiny and fast carousel slider that transitions between items with card-like animations.

It is built using HTML, CSS, and plain JavaScript. The HTML structure defines the carousel container and individual cards. The CSS styles create the stacked card effect, with each card having different positions, scales, and rotations. The JavaScript enables navigation between cards and manages the animation transitions.

How to use it:

1. Create a container element for the carousel, a wrapper for the cards, individual card elements, and next/prev controls.

<div class="mvp-carousel" data-visible="3">
  <div class="mvp-carousel-wrapper">
    <div class="mvp-card isHidden">12</div>
    <div class="mvp-card isHidden">11</div>
    <div class="mvp-card isHidden">10</div>
    <div class="mvp-card isHidden">9</div>
    <div class="mvp-card isHidden">8</div>
    <div class="mvp-card isHidden">7</div>
    <div class="mvp-card isHidden">6</div>
    <div class="mvp-card isHidden">5</div>
    <div class="mvp-card isHidden">4</div>
    <div class="mvp-card mvp-card--bottom">3</div>
    <div class="mvp-card mvp-card--middle">2</div>
    <div class="mvp-card mvp-card--active">1</div>
  </div>
  <button class="mvp-carousel__prevBtn"></button>
  <button class="mvp-carousel__nextBtn"></button>
</div>

2. Define styles for the carousel container, wrapper, and cards. The cards have specific classes depending on their position (active, middle, bottom) and transitions for smooth animation.

.mvp-carousel {
  overflow: hidden;
  padding: 3rem;
  position: relative;
  margin: 5rem auto 0 auto;
  width: 20rem;
  box-shadow: 0 0 6rem -1rem #00000048;
}
.mvp-carousel-wrapper {
  display: flex;
  transition: transform .5s ease;
  position: relative;
}
.mvp-card {
  display: flex;
  justify-content: center;
  align-items: center;
  flex: 0 0 12rem;
  min-height: 17rem;
  position: relative;
  left: -100%;
  background: rgb(85, 122, 192);
  box-sizing: border-box;
  padding: 1rem;
  font-size: 1.4rem;
  font-family: Arial, Helvetica, sans-serif;
  text-align: center;
  transition: opacity .6s, background 1.2s, transform .8s, left .5s;
  transform: scale(.75) rotate(5deg);
  box-shadow: 0 0 2rem 0 #00000048;
}
.mvp-card--bottom {
  left: 1.8rem;
  transform: scale(0.9)  rotate(0);
  z-index: 1;
}
.mvp-card--middle {
  left: -8.5rem;
  transform: scale(0.98)  rotate(0);
  z-index: 2;
}
.mvp-card--active {
  transform: scale(1.1) rotate(0);
  opacity: 1;
  background: rgb(22, 32, 51);
  color: white;
  z-index: 3;
  left: -18.5rem;
}
.isHidden{
  opacity: 0;
  pointer-events: none;
  z-index: 0;
}
.z-index-high{
  z-index: 6;
}
.mvp-carousel__prevBtn,
.mvp-carousel__nextBtn {
  position: absolute;
  background: none;
  top: 50%;
  padding: 10px;
  border: solid rgb(22, 32, 51);
  border-width: 0 3px 3px 0;
  display: inline-block;
  cursor: pointer;
}
.mvp-carousel__nextBtn {
  left: 1.5rem;
  transform: rotate(135deg);
}
.mvp-carousel__prevBtn {
  right: 1.5rem;
  transform: rotate(-45deg);
}

3. Create a Carousel class to handle the functionality. It keeps track of the active card, listens for user interactions (clicks on the next/previous buttons), and updates the card positions and classes accordingly.

class Carousel {
  constructor() {
    this.container = document.querySelector('.mvp-carousel');
    this.carousel = this.container.querySelector('.mvp-carousel-wrapper');
    this.cards = Array.from(this.carousel.querySelectorAll('.mvp-card'));
    this.prevBtn = this.container.querySelector('.mvp-carousel__prevBtn');
    this.nextBtn = this.container.querySelector('.mvp-carousel__nextBtn');
    this.numVisible = parseInt(this.container.dataset.visible);
    this.activeIndex = this.cards.length - 3;
    this.render('z-index-low');
    this.setupEventListeners();
    this.setupResizeListener();
  }
  next() {
    this.activeIndex++;
    this.render('z-index-low');
    this.prevBtn.classList.remove('isHidden');
    if (this.activeIndex >= this.cards.length - 3 ) {
      this.nextBtn.classList.add('isHidden');
    }
  }
  prev() {
    this.activeIndex--;
    this.render('z-index-high');
    this.nextBtn.classList.remove('isHidden');
    if (this.activeIndex <= -2) {
      this.prevBtn.classList.toggle('isHidden');
    }
  }
  render(zIndex) {
    const cardWidth = this.cards[0].offsetWidth;
    const offsetX = -(this.activeIndex * cardWidth);
    const cardLength = this.cards.length;
    this.carousel.style.transform = `translateX(${offsetX}px)`;
    this.cards.forEach((card, index) => {
      const position = index - this.activeIndex;
      const isVisible = position >= 0 && position < this.numVisible;
      const classes = {
        'mvp-card--active': isVisible && position === 2,
        'mvp-card--middle': isVisible && position === 1,
        'mvp-card--bottom': isVisible && position === 0,
      };
      if (this.activeIndex + 2 < cardLength) {
        card.classList.toggle( zIndex, !isVisible);
        card.classList.toggle('isHidden', !isVisible);
        Object.entries(classes).forEach(([className, condition]) => {
          card.classList.toggle(className, condition);
        });
      }
    });
  }
  setupEventListeners() {
    this.nextBtn.addEventListener('click', () => this.next());
    this.prevBtn.addEventListener('click', () => this.prev());
  }
  setupResizeListener() {
    window.addEventListener('resize', () => this.render());
  }
}
const carousel = new Carousel();

You Might Be Interested In:


Leave a Reply