Search code examples
javascripthtmlcsssliderswiper.js

SwiperJs: I'm displaying groups of 2 slides, they should be centered but I can't even achieve it restraining the slides width


I am working with SwiperJS to create a slider that displays two slides per group, centered within the slider's container. My current implementation results in the slides expanding to fill the entire available width of the container, which is not what I want. Ideally, I'd like the slides to occupy only part of the container's width while remaining centered.

CodeSandbox Example:

Please refer to my CodeSandbox example here for a live demo of the issue.

Attempted Solutions:

  • I tried using flex, justify-content: center, and margin-inline: auto with width: fit-content for the slides.
  • I attempted to limit the swiper-container width.
  • None of these approaches have corrected the issue, suggesting that I might be missing something obvious. This should be simpler.

Here is what the current layout looks like: enter image description here

Here is what I want to achieve (desired layout): enter image description here

Note: the prev-arrow is not relevant, I'm just focused in achieve the centering.

Relavant code:

Javascript

$.getScript(
      "https://cdn.jsdelivr.net/npm/swiper@11/swiper-bundle.min.js",
      function () {
        new Swiper(".customSwiper", {
          grabCursor: true,
          slidesPerView: 2,
          centeredSlides: false,
          spaceBetween: 10,
          loop: false,  
          slidesPerGroup: 2,  
          navigation: {
            nextEl: '.swiper-button-next',
            prevEl: '.swiper-button-prev',
          },
        });
      }
    );

CSS:

/* swiper */
.swiper-slide {
  display: flex;
  justify-content: center;
  align-items: center;
  height: 100%;
  width: 100%;
  max-width: unset !important;
}
.swiper-container {
  width: 100vw;
  height: 100%;
  overflow: hidden;
  position: relative;
  background: #FFF;
  max-width: unset !important;
}
/* card being displayed */
.card {
  border-radius: 25px;
  background: #F8F8F8;
  box-shadow: 0px 0px 8px 0px rgba(0, 0, 0, 0.05);
  padding: 12px;
  display: grid;
  grid-template-columns: 1fr 5fr;
  max-width: 30em;
  width: fit-content;
  column-gap: 24px;
  }

Question: How can I adjust my SwiperJS configuration or CSS to prevent the slides from stretching to fill the entire container width and instead center them as I've illustrated? Are there specific CSS properties or Swiper settings that could correct this behavior?


Solution

  • Since the cards are grouped in twos, the "odd" cards would need to be aligned to the right, while the "even" cards would be aligned to the left. Thus, we can use :nth-child(odd) and :nth-child(even) respectively to align them as such:

    .card {
      …
     /**
      * Remove:
      * margin: 0 auto;
      */
    }
      
    .swiper-slide:nth-child(odd) .card {
      margin-left: auto;
    }
    
    .swiper-slide:nth-child(even) .card {
      margin-right: auto;
    }
    

    document.addEventListener('DOMContentLoaded', function () {
      const newCards = [
        {
          profilePhotoSrc:
            'https://ik.imagekit.io/ei6mtk4ll/Stopwatts/SW-008/sw-008-card-1.png',
          testimonial:
            'I’m so surprised by the amount we saved with these ESaver Watt devices… literally, you just plug them in and that’s it! My wife was shocked when we got our first bill and we saved $35! And it’s only gotten better from there… We’ll be customers for life.',
          profileName: 'Kevin Holmes, St. Louis, MO',
          reviewStartsImgSrc:
            'https://powerwattwise.com/es9pwtyk/images/checkout-now-v1/5-stars.png',
          rating: '5/5',
          saved: '$35',
        },
        {
          profilePhotoSrc:
            'https://ik.imagekit.io/ei6mtk4ll/Stopwatts/SW-008/sw-008-card-2.png', // Assuming a placeholder URL
          title: '4.7/5 Verified Rating',
          testimonial:
            'I don’t usually write reviews, but I have to share some numbers with you all… In the first month, we saved $33. The second month, $45. The third month, $52. Fourth month, $55. If that isn’t a strong testimonial, I’m not sure what is!',
          profileName: 'Melisa Houston, Syracuse, NY',
          reviewStartsImgSrc:
            'https://powerwattwise.com/es9pwtyk/images/checkout-now-v1/4.5-stars.png', // Assuming a placeholder URL
          rating: '4.7/5',
          saved: '$55',
        },
        {
          profilePhotoSrc:
            'https://ik.imagekit.io/ei6mtk4ll/Stopwatts/SW-008/sw-008-card-3.png', // Assuming a placeholder URL
          title: '5/5 Verified Rating',
          testimonial:
            'If you’re skeptical, I feel sorry for you. ESaver Watt has really made something special here. I’m not entirely sure how it works, but the savings are REAL!',
          profileName: 'Brenda Shearer, Syracuse, NY',
          reviewStartsImgSrc:
            'https://powerwattwise.com/es9pwtyk/images/checkout-now-v1/5-stars.png', // Assuming a placeholder URL
          rating: '5/5',
          saved: '$50',
        },
        {
          profilePhotoSrc:
            'https://ik.imagekit.io/ei6mtk4ll/Stopwatts/SW-008/sw-008-card-4.png', // Assuming a placeholder URL
          title: '4/5 Verified Rating',
          testimonial:
            'Alright so I ended up buying 3 of these. Put one in my kitchen, one in the bedroom, and one in our living room. After six months, I can confidently say that we’re easily saving at least $50 per month. ESaver Watt is a no brainer. You want to save money each month? Buy a few of these and you’re all set.',
          profileName: 'Wilma Besley, Orlando, FL',
          reviewStartsImgSrc:
            'https://powerwattwise.com/es9pwtyk/images/checkout-now-v1/4.5-stars.png', // Assuming a placeholder URL
          rating: '4/5',
          saved: '$50',
        },
      ];
    
      newCards.forEach((card) => {
        const swiperSlide = document.createElement('div');
        swiperSlide.className = 'swiper-slide';
        swiperSlide.innerHTML = `
          <div class="card">
            <img src="${card.profilePhotoSrc}" alt="${card.profileName}" style="width:100px; height:100px; border-radius:50%;">
            <h3>${card.profileName}</h3>
            <p>${card.testimonial}</p>
            <img src="${card.reviewStartsImgSrc}" alt="Rating ${card.rating}" style="width:100px;">
            <p>Saved: ${card.saved}</p>
          </div>
        `;
        document.querySelector('.swiper-wrapper').appendChild(swiperSlide);
      });
    
      // Initialize Swiper
      new Swiper('.customSwiper', {
        grabCursor: true,
        slidesPerView: 2,
        centeredSlides: false,
        spaceBetween: 24,
        loop: false,
        slidesPerGroup: 2,
        updateOnImagesReady: true,
        navigation: {
          nextEl: '.swiper-button-next',
          prevEl: '.swiper-button-prev',
        },
      });
    });
    html,
    body {
      position: relative;
      height: 100%;
    }
    body {
      background: #eee;
      font-family: Arial, sans-serif;
      margin: 0;
      padding: 0;
    }
    swiper-slide {
      display: flex;
      justify-content: center;
      align-items: center;
      height: 100%;
      width: 100%;
      max-width: unset !important;
    }
    .main-slider .swiper-slide {
      box-shadow: 0px 10px 30px rgba(0, 0, 0, 0.05);
      height: 100%;
      width: 100%; /* Adjust this to manage the total width of each slide containing two cards */
      flex-shrink: 0;
      padding: 0 !important;
    }
    
    .swiper {
      padding: 0 15% !important;
    }
    
    .swiper-wrapper {
      height: 100%;
      width: 100%;
      align-items: center;
    }
    .card {
      border-radius: 25px;
      background: #f8f8f8;
      box-shadow: 0 0 8px rgba(0, 0, 0, 0.05);
      padding: 20px;
      max-width: 300px;
    }
    
    .swiper-slide:nth-child(odd) .card {
      margin-left: auto;
    }
    
    .swiper-slide:nth-child(even) .card {
      margin-right: auto;
    }
    <link
      rel="stylesheet"
      href="https://cdn.jsdelivr.net/npm/swiper@11/swiper-bundle.min.css"
    />
    <script src="https://cdn.jsdelivr.net/npm/swiper@11/swiper-bundle.min.js"></script>
    <body>
      <!-- Swiper -->
      <div class="swiper customSwiper main-slider">
        <div class="swiper-wrapper">
          <!-- Dynamic card creation will be inserted here -->
        </div>
        <div class="swiper-button-next"></div>
        <div class="swiper-button-prev"></div>
      </div>
    </body>