Product Card slider parallax effect using HTML, CSS, and JavaScript

By Bytewebster - October 9, 2022



Welcome to the bytewebster Project blogs. In this JavaScript project, we will show you how to create a Product Card Slider Parallax Effect. Which will be made using only HTML, CSS, and Javascript.

Working:

This product card slider is like a carousel, it also has navigation buttons from the bottom. With the help of these buttons you can go to different slides. In this slider we have placed 5 product cards but you can make them more or less according to your choice. And as soon as you move from one slide to another, the background of each slide will also change. or an add to cart button is also given in every card. And there is also space for each product's details, pricing and its details.

                     
                 

Detailed Overview of Project


If you want to make this Product Card slider parallax effect by yourself without downloading the source code files. So then here you have to create three main files The first file will be HTML second will be CSS and the last will be JavaScript and then you have to take those files to your text editor where you will create this project.


HTML Structure


The first thing to note is that there are two CDN links in the head section: one from Google Fonts and another from Bootstrap Icons. The line after these links is an unordered list of items with each item containing a paragraph of text followed by an image.

Its HTML structure only looks big, that's because we have made only one card and slide in it. We have just copied and pasted the remaining four cards from the first one. But we have used different CSS for each card such as the background colors and details of cards and slides.

We have given its complete code below, you can copy paste it or know about it. So now let's move on to its styling and its JavaScript part.


<div class="wrapper">
      <div class="card card--19">
        <div class="card__header card__header--19">
          <div class="card__watermark" data-watermark="Air"></div>

          <img src="https://i.ibb.co/q7RKcZk/nike.png" alt="Nike" class="card__logo card__will-animate">

          <span class="card__price card__will-animate">$120</span>

          <h1 class="card__title card__will-animate">Air Structure 1</h1>
          <span class="card__subtitle card__will-animate">From the Flymesh upper to the triple-density foam midsole, the Nike Air Zoom Structure 19 Men's Running Shoe offers plenty of support and the response you need for a smooth, stable ride that feels ultra fast.</span>
        </div>
        <div class="card__body">
          <img src="https://i.ibb.co/R0Y8T8r/nike19.png" alt="Nike 19" class="card__image card__will-animate">
          <div class="card__wish-list card__wish-list--19 card__will-animate"><i class="bi bi-cart"></i> ADD TO CART</div>

          <span class="card__category card__will-animate">Men's running shoe</span>
        </div>
      </div>
      <!-- card end -->
      <div class="card card--solstice">
        <div class="card__header card__header--solstice">
          <div class="card__watermark" data-watermark="Classic"></div>

          <img src="https://i.ibb.co/q7RKcZk/nike.png" alt="Nike" class="card__logo card__will-animate">

          <span class="card__price card__will-animate">$129</span>

          <h1 class="card__title card__will-animate">Air Solstice QS</h1>
          <span class="card__subtitle card__will-animate">The Nike Air Solstice draws inspiration from the swoosh's classic running shoes of the 1980's updating the style with premium materials and impressive production quality.</span>

        </div>
        <div class="card__body">
          <img src="https://i.ibb.co/ZMVHp6x/nike-air-solstice.png" alt="Nike Solstice" class="card__image card__will-animate">
          <div class="card__wish-list card__wish-list--solstice card__will-animate"><i class="bi bi-cart"></i> ADD TO CART</div>

          <span class="card__category card__will-animate">Men's shoe</span>
        </div>
      </div>
      <!-- card end -->
      <div class="card card--huarache">
        <div class="card__header card__header--huarache">
          <div class="card__watermark" data-watermark="Safari"></div>

          <img src="https://i.ibb.co/q7RKcZk/nike.png" alt="Nike" class="card__logo card__will-animate">

          <span class="card__price card__will-animate">$140</span>

          <h1 class="card__title card__will-animate">Air Huarache Utility</h1>
          <span class="card__subtitle card__will-animate">The Nike Air Huarache Utility Men's Shoe toughens up a famous running shoe with a nylon upper, fused mudguard and vibrant detail.</span>

        </div>
        <div class="card__body">
          <img src="https://i.ibb.co/9bc3SYK/nike-safari.png" alt="Nike Huarache" class="card__image card__will-animate">
          <div class="card__wish-list card__wish-list--solstice card__will-animate"><i class="bi bi-cart"></i> ADD TO CART</div>

          <span class="card__category card__will-animate">Men's shoe</span>
        </div>
      </div>
      <!-- card end -->
      <div class="card card--huarache">
        <div class="card__header card__header--bytewebster">
          <div class="card__watermark" data-watermark="BYTEWEBSTER"></div>

          <img src="https://i.ibb.co/q7RKcZk/nike.png" alt="Nike" class="card__logo card__will-animate">

          <span class="card__price card__will-animate">$190</span>

          <h1 class="card__title card__will-animate">Sneakers shoe Nike ONE</h1>
          <span class="card__subtitle card__will-animate">Nike offers a variety of skateboarding shoes for different riding styles, so you can find the perfect pair for your skating needs.</span>

        </div>

        <div class="card__body">
          <img src="images/m_shoe4.png" alt="Nike Huarache" class="card__image card__will-animate">
          <div class="card__wish-list card__wish-list--bytewebster card__will-animate"><i class="bi bi-cart"></i> ADD TO CART</div>

          <span class="card__category card__will-animate">Men's shoe</span>
        </div>
      </div>
      <!-- card end -->
      <div class="card card--huarache">
        <div class="card__header card__header--webster">
          <div class="card__watermark" data-watermark="WEBSTER"></div>

          <img src="https://i.ibb.co/q7RKcZk/nike.png" alt="Nike" class="card__logo card__will-animate">

          <span class="card__price card__will-animate">$210</span>

          <h1 class="card__title card__will-animate">Sports shoe Nike ONE</h1>
          <span class="card__subtitle card__will-animate">Nike offers a variety of skateboarding shoes for different riding styles, so you can find the perfect pair for your skating needs.</span>
        </div>

        <div class="card__body">
          <img src="images/m_shoe5.png" alt="Nike Huarache" class="card__image card__will-animate">
          <div class="card__wish-list card__wish-list--webster card__will-animate"><i class="bi bi-cart"></i> ADD TO CART</div>
          <span class="card__category card__will-animate">Men's shoe</span>
        </div>
      </div>
      <!-- card end -->
    </div>
    <div class="cards-placeholder">
      <div class="cards-placeholder__item"></div>
      <div class="cards-placeholder__item"></div>
      <div class="cards-placeholder__item"></div>
      <div class="cards-placeholder__item"></div>
      <div class="cards-placeholder__item"></div>
    </div>


Styling With CSS


its CSS code starts with a body tag that has height: 100%; width: 100%; margin: 0; padding: 0; The body is the wrapper for all of the cards in the card stack, so it's important to make sure that there is enough space for them.

The overflow property sets how much content can be shown on each side of the browser window and hides any content that would otherwise spill outside of this area. Next, we have a .wrapper div which contains an .card element inside it and defines its position relative to itself (positioning relative means that it's positioned next to another element).

This allows us to place our card elements anywhere on screen without having to worry about their absolute positioning values being off by default because they're not fixed in one spot like other elements are when they're placed absolutely. Finally, we have a class called .card which specifies some styles for our card container such as display block and top 25px.

Finally, we have transition: background-color 0.2s; which transitions between colors every 2 seconds when you scroll up or down on your browser window. The last part of this code is where it gets interesting because it uses CSS3 properties like position: relative; overflow-x: hidden; width:

Here is the code for styling. Now it's a JavaScript project, let's focus on the JavaScript part.


html,
body {
  height: 100%;
  width: 100%;
  margin: 0;
  padding: 0;

  font-family: "Roboto", "Helvetica", sans-serif;

  transition: background-color 0.2s;
  will-change: background-color;
}

.wrapper {
  position: relative;
  overflow-x: hidden;
  width: 100%;
  height: 100%;
}

.card {
  display: block;
  position: absolute;
  top: 25px;
  margin: 0 auto;
  width: 350px;
  background-color: #fff;
  border-radius: 15px;

  box-shadow: 0 30 50 rgba(0, 0, 0, 0.2);

  transform: translateX(-50%);
  transition: left 0.5s ease-out;
  will-change: left;

  -webkit-user-select: none;
  -moz-user-select: none;
  -ms-user-select: none;
  -o-user-select: none;
  user-select: none;
}

.card--19 {
  left: 50%;
}

.card--solstice,
.card--huarache {
  left: 150%;
}

.card__header {
  position: relative;
  height: 170px;
  padding: 30px 30px 300px;
  border-top-right-radius: 15px;
  border-top-left-radius: 15px;
  color: #fff;
}

.card__header--19 {
  background-color: #F72648;
  background-image: linear-gradient(#F72648, #FCCB3C);

  background: #F72648;
  background: linear-gradient(#F72648, #FCCB3C);
}

.card__header--solstice {
  background-color: #3CA3FC;
  background-image: linear-gradient(#3CA3FC, #FFD300);

  background: #3CA3FC;
  background: linear-gradient(#3CA3FC, #FFD300);
}

.card__header--huarache {
  background-color: #26C9F7;
  background-image: linear-gradient(#26C9F7, #DFFC3C);

  background: #26C9F7;
  background: linear-gradient(#26C9F7, #DFFC3C);
}

.card__header--bytewebster {
  background-color: #36C8F7;
  background-image: linear-gradient(#36C8F7, #F7C236);

  background: #36C8F7;
  background: linear-gradient(#36C8F7, #F7C236);
}

.card__header--webster {
  background-color: #9E9BFF;
  background-image: linear-gradient(#9E9BFF, #9BFF93);

  background: #9E9BFF;
  background: linear-gradient(#9E9BFF, #9BFF93);
}

.card__watermark {
  overflow: hidden;
  position: absolute;
  bottom: 10px;
  left: 0;
  width: 100%;
}

.card__watermark::after {
  content: attr(data-watermark);
  position: relative;
  left: -20px;
  color: rgba(0, 0, 0, .3);
  font-size: 240px;
  font-weight: 700;
  text-transform: uppercase;
}

.card__logo {
  width: 50px;
  height: auto;
}

.card__price {
  float: right;
  font-size: 16px;
  font-weight: 300;
}

.card__title {
  margin: 35px 0 20px;
  font-size: 15px;
  line-height: 1.1em;
  text-transform: uppercase;
  letter-spacing: 1.5px;
}

.card__subtitle {
  display: block;
  font-size: 13px;
  font-weight: 300;
}

.card__body {
  position: relative;
  padding: 40px 30px 20px;
}

.card__image {
  z-index: 1;
  position: absolute;
  top: -290px;
  left: -30px;
  width: 125%;

  user-select: none;
  -moz-user-select: none;
  -webkit-user-drag: none;
  -webkit-user-select: none;
  -ms-user-select: none;
}

.card__wish-list {
  display: block;
  width: 50%;
  margin: 0 auto 15px;
  padding: 15px;
  border: 2px solid #fff;
  border-radius: 20px;
  text-align: center;
  text-transform: uppercase;
  font-size: 14px;
}

.card__wish-list--19 {
  color: #8850FF;
  border-color: #8850FF;
}


.card__wish-list--solstice {
  color: #FFBA00;
  border-color: #FFBA00;
}

.card__wish-list--huarache {
  color: #26C9F7;
  border-color: #26C9F7;
}

.card__wish-list--bytewebster{
  color: #1C75F6;
  border-color: #1C75F6;
}

.card__wish-list--webster{
  color: #FA0C0C;
  border-color: #FA0C0C;
}

.card__category {
  display: block;
  font-size: 12px;
  color: #AEAEAE;
  text-transform: uppercase;
  text-align: center;
}

.card__will-animate {
  will-change: transform;
}

.cards-placeholder {
  display: block;
  position: relative;
  bottom: 40px;
  text-align: center;
}

.cards-placeholder__item {
  opacity: 0.3;
  display: inline-block;
  margin-right: 10px;
  background-color: #fff;
  width: 30px;
  height: 5px;
  border-radius: 5px;

  transition: opacity 0.2s;
  will-change: opacity;
}

.cards-placeholder__item--active {
  opacity: 1;
}


JavaScript Explanation


Its starts by declaring a variable called BODY_BACKGROUNDS. This is an array of colors that will be used to create the background for each card. Next, it declares a function called Slider(). This function has two parameters: cards and currentIndex.

The cards parameter is an array of objects that represent all the cards in the slider, while currentIndex is set to 0. The next line creates an event listener on touchstart which will call onStart() when touched; this method also binds itself to mousemove and touchend events as well as mousedown and mouseup events so they can be handled properly later on in the code.

Next, it sets active placeholder with setActivePlaceholder(), which calls initEvents() when initialized so that any new touch or mouse events are handled appropriately within this function. The code is a function that is executed when the page loads.

The code initializes all of the events for the slider, and then sets the active placeholder to be whatever is in index 0 after that we declaring the Slider object. The constructor function is then called, which initializes all of the variables and properties for this object.

The onEnd event handler is then declared and assigned to a function named onEnd(). This function will be executed when the user releases their mouse button after dragging it over the slider. In order to calculate how far they have dragged, we need to know where they started from and where they are now in relation to that starting point

We do this with two variables: startX and currentX. These values are initialized at 0 (the left-most position) because we want them both set at 0 before any movement has been made so that our calculations can be accurate.

Next, if there was a change in direction during their drag (diff > 0), we assign an appropriate value based on whether or not it's moving left or right using Math's abs() method - if diff is greater than 4/5ths of window width, then direction becomes 'left' or 'right'.


(function () {
  'use strict';

  var BODY_BACKGROUNDS = [
    '#8850FF',
    '#FFBA00',
    '#4054FF',
    '#FE398D',
    '#E5BC49'
  ];

  function Slider () {
    this.cards = document.querySelectorAll('.card');
    this.currentIndex = 0;

    this.isDragging = false;
    this.startX = 0;
    this.currentX = 0;

    this.initEvents();
    this.setActivePlaceholder();
  }

  // initialize drag events
  Slider.prototype.initEvents = function () {
    document.addEventListener('touchstart', this.onStart.bind(this));
    document.addEventListener('touchmove', this.onMove.bind(this));
    document.addEventListener('touchend', this.onEnd.bind(this));

    document.addEventListener('mousedown', this.onStart.bind(this));
    document.addEventListener('mousemove', this.onMove.bind(this));
    document.addEventListener('mouseup', this.onEnd.bind(this));

  };

  // set active placeholder
  Slider.prototype.setActivePlaceholder = function () {
    var placeholders = document.querySelectorAll('.cards-placeholder__item');
    var activePlaceholder = document.querySelector('.cards-placeholder__item--active')

    if (activePlaceholder) {
      activePlaceholder.classList.remove('cards-placeholder__item--active');
    }

    placeholders[this.currentIndex].classList.add('cards-placeholder__item--active');

    var bodyEl = document.querySelector('body');
    bodyEl.style.backgroundColor = BODY_BACKGROUNDS[this.currentIndex];
  };

  // mousedown event
  Slider.prototype.onStart = function (evt) {
    this.isDragging = true;

    this.currentX = evt.pageX || evt.touches[0].pageX;
    this.startX = this.currentX;

    var card = this.cards[this.currentIndex];

    // calculate ration to use in parallax effect
    this.windowWidth = window.innerWidth;
    this.cardWidth = card.offsetWidth;
    this.ratio = this.windowWidth / (this.cardWidth / 4);
  };

  // mouseup event
  Slider.prototype.onEnd = function (evt) {
    this.isDragging = false;

    var diff = this.startX - this.currentX;
    var direction = (diff > 0) ? 'left' : 'right';
    this.startX = 0;

    if (Math.abs(diff) > this.windowWidth / 4) {
      if (direction === 'left') {
        this.slideLeft();
      } else if (direction === 'right') {
        this.slideRight();
      } else {
        this.cancelMoveCard();
      }

    } else {
      this.cancelMoveCard();

    }

  };

  // mousemove event
  Slider.prototype.onMove = function (evt) {
    if (!this.isDragging) return;

    this.currentX = evt.pageX || evt.touches[0].pageX;
    var diff = this.startX - this.currentX;
    diff *= -1;

    // don't let drag way from the center more than quarter of window
    if (Math.abs(diff) > this.windowWidth / 4) {
      if (diff > 0) {
        diff = this.windowWidth / 4;
      } else {
        diff = - this.windowWidth / 4;
      }
    }

    this.moveCard(diff);
  };

  // slide to left direction
  Slider.prototype.slideLeft = function () {
    // if last don't do nothing
    if (this.currentIndex === this.cards.length - 1) {
      this.cancelMoveCard();
      return;
    }

    var self = this;
    var card = this.cards[this.currentIndex];
    var cardWidth = this.windowWidth / 2;

    card.style.left = '-50%';

    this.resetCardElsPosition();

    this.currentIndex += 1;
    this.setActivePlaceholder();
    card = this.cards[this.currentIndex];

    card.style.left = '50%';

    this.moveCardEls(cardWidth * 3);

    // add delay to resetting position
    setTimeout(function () {
      self.resetCardElsPosition();
    }, 50);
  };

  // slide to right direction
  Slider.prototype.slideRight = function () {
    // if last don't do nothing
    if (this.currentIndex === 0) {
      this.cancelMoveCard();
      return;
    }

    var self = this;
    var card = this.cards[this.currentIndex];
    var cardWidth = this.windowWidth / 2;

    card.style.left = '150%';

    this.resetCardElsPosition();

    this.currentIndex -= 1;
    this.setActivePlaceholder();
    card = this.cards[this.currentIndex];

    card.style.left = '50%';

    this.moveCardEls(-cardWidth * 3);

    // add delay to resetting position
    setTimeout(function () {
      self.resetCardElsPosition();
    }, 50);
  };

  // put active card in original position (center)
  Slider.prototype.cancelMoveCard = function () {
    var self = this;
    var card = this.cards[this.currentIndex];

    card.style.transition = 'transform 0.5s ease-out';
    card.style.transform = '';

    this.resetCardElsPosition();
  };

  // reset to original position elements of card
  Slider.prototype.resetCardElsPosition = function () {
    var self = this;
    var card = this.cards[this.currentIndex];

    var cardLogo = card.querySelector('.card__logo');
    var cardPrice = card.querySelector('.card__price');
    var cardTitle = card.querySelector('.card__title');
    var cardSubtitle = card.querySelector('.card__subtitle');
    var cardImage = card.querySelector('.card__image');
    var cardWishList = card.querySelector('.card__wish-list');
    var cardCategory = card.querySelector('.card__category');
    var cardWillAnimate = card.querySelectorAll('.card__will-animate');

    // move card elements to original position
    cardWillAnimate.forEach(function (el) {
      el.style.transition = 'transform 0.5s ease-out';
    });

    cardLogo.style.transform = '';
    cardPrice.style.transform = '';

    cardTitle.style.transform = '';
    cardSubtitle.style.transform = '';

    cardImage.style.transform = '';
    cardWishList.style.transform = '';
    cardCategory.style.transform = '';

    // clear transitions
    setTimeout(function () {
      card.style.transform = '';
      card.style.transition = '';

      cardWillAnimate.forEach(function (el) {
        el.style.transition = '';
      });
    }, 500);

  };

  // slide card while dragging
  Slider.prototype.moveCard = function (diff) {

    var card = this.cards[this.currentIndex];

    card.style.transform = 'translateX(calc(' + diff + 'px - 50%))';
    diff *= -1;

    this.moveCardEls(diff);
  };

  // create parallax effect on card elements sliding them
  Slider.prototype.moveCardEls = function (diff) {
    var card = this.cards[this.currentIndex];

    var cardLogo = card.querySelector('.card__logo');
    var cardPrice = card.querySelector('.card__price');
    var cardTitle = card.querySelector('.card__title');
    var cardSubtitle = card.querySelector('.card__subtitle');
    var cardImage = card.querySelector('.card__image');
    var cardWishList = card.querySelector('.card__wish-list');
    var cardCategory = card.querySelector('.card__category');
    var cardWillAnimate = card.querySelectorAll('.card__will-animate');

    cardLogo.style.transform = 'translateX(' + (diff / this.ratio) + 'px)';
    cardPrice.style.transform = 'translateX(' + (diff / this.ratio) + 'px)';

    cardTitle.style.transform = 'translateX(' + (diff / (this.ratio * 0.90)) + 'px)';
    cardSubtitle.style.transform = 'translateX(' + (diff / (this.ratio * 0.85)) + 'px)';

    cardImage.style.transform = 'translateX(' + (diff / (this.ratio * 0.35)) + 'px)';

    cardWishList.style.transform = 'translateX(' + (diff / (this.ratio * 0.85)) + 'px)';
    cardCategory.style.transform = 'translateX(' + (diff / (this.ratio * 0.65)) + 'px)';

  };


  // create slider
  var slider = new Slider();

})();

Thank you for spending your valuable time in reading this article. We hope you liked the project.




Video of the Project

                     
                     
                 

Take This Short Survey!


Download Source Code Files

From here You can download the source code files of this product Card slider parallax effect.
If you are just starting in web development, these snippets will be useful. We would appreciate it if you would share our blog posts with other like-minded people.


Download Source Code
Please wait ...
If the download didn't start automatically, click here

ByteWebster Play and Win Offer.

PLAY A SIMPLE GAME AND WIN PREMIUM WEB DESIGNS WORTH UPTO $100 FOR FREE.

PLAY FOR FREE





Connect With Us

we would like to keep in touch with you..... Register Here.

JOIN US JOIN TELEGRAM