Search code examples
javascripthtmlcss

How to center items in carousel slider?


I am currently working on a country flag slider with around 14 different country flags.

My desired animation is that there is a container/card showing only 3 countries on the card, where it slides after 2 seconds:

Country on the left moves out of the container Country on the middle moves to the left Country on the right goes to the middle and scales a little bit (so it pops a bit more out) while moving to it.

And a new country moves to the right side.

The issue I'm encountering is that I can't figure out how to center the middle image into the middle of the card, since the way I've implemented it is that there are 14 images and when I use justify-content: center; the Philippines shows on the card in the middle which is normal but not the desired outcome.

What I have tried so far:

  • Using pixels and calculate the amount it has to move but this doesn't make it responsive and I would like it to be responsive.
  • Justify-content: center; on the div

What currently happens: [Click] Desired animation: [Click]

This is my first Stackoverflow post and I hope I explained everything clearly, if not please feel free to give feedback on how I can improve my post.

Code:

const slider = document.querySelector('.flag-slider');
const flags = document.querySelectorAll('.flag');
let currentIndex = 2; // Middle flag

function updateFlags() {
  flags.forEach((flag, index) => {
    flag.classList.remove('active');
    if (index === currentIndex - 1) {
      flag.classList.add('active');
    }
  });
}

function slideFlags() {
  // Slide to the left
  slider.style.transform = `translateX(-${(currentIndex - 1) * (75 / 3)}%)`;

  currentIndex++;

  if (currentIndex > flags.length) {
    console.log('reset');
    currentIndex = 2;
    slider.style.transform = `translateX(0%)`;
  }

  updateFlags();
}

// Initial flag setup
updateFlags();

// Auto-slide every 2 seconds
setInterval(slideFlags, 2000);
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

body {
  font-family: Arial, sans-serif;
  background-color: #f0f0f0;
}

.countries {
  display: flex;
  flex-direction: column;
  justify-content: center;
  width: 300px;
  padding: 20px;
}

.slider-container {
  width: 100%;
  margin: 50px auto;
  overflow: hidden;
  position: relative;
}

.flag-slider {
  display: flex;
  transition: transform 0.5s ease-in-out;
}

.flag,
.last_flag {
  width: 33.33%;
  padding: 10px;
  display: flex;
  justify-content: center;
  align-items: center;
  transition: transform 0.5s ease-in-out, opacity 0.5s ease-in-out;
}

.flag img {
  width: 100%;
  object-fit: contain;
}

.flag.active {
  transform: scale(1.2);
}
<html class="no-js" lang="">

<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title></title>
  <link rel="stylesheet" href="css/style.css">
  <meta name="description" content="">
  <meta property="og:title" content="">
  <meta property="og:type" content="">
  <meta property="og:url" content="">
  <meta property="og:image" content="">
  <meta property="og:image:alt" content="">
  <link rel="icon" href="/favicon.ico" sizes="any">
  <link rel="icon" href="/icon.svg" type="image/svg+xml">
  <link rel="apple-touch-icon" href="icon.png">
  <link rel="manifest" href="site.webmanifest">
  <meta name="theme-color" content="#fafafa">
</head>

<body>

  <div class="countries">
    <div class="slider-container">
      <div class="flag-slider">
        <img class="flag" src="https://picsum.photos/200" alt="Australia">
        <img class="flag" src="https://picsum.photos/200" alt="Austria">
        <img class="flag" src="https://picsum.photos/200" alt="Brazil">
        <img class="flag" src="https://picsum.photos/200" alt="Canada">
        <img class="flag" src="https://picsum.photos/200" alt="France">
        <img class="flag" src="https://picsum.photos/200" alt="Germany">
        <img class="flag" src="https://picsum.photos/200" alt="India">
        <img class="flag" src="https://picsum.photos/200" alt="Mexico">
        <img class="flag" src="https://picsum.photos/200" alt="Philippines">
        <img class="flag" src="https://picsum.photos/200" alt="South Africa">
        <img class="flag" src="https://picsum.photos/200" alt="Egypt">
        <img class="flag" src="https://picsum.photos/200" alt="UK">
        <img class="flag" src="https://picsum.photos/200" alt="USA">
        <img class="flag" src="https://picsum.photos/200" alt="Venezuela">
        <img class="flag" src="https://picsum.photos/200" alt="Australia">
        <img class="last_flag" src="https://picsum.photos/200" alt="Austria">
      </div>
    </div>
    <span>Different countries</span>
  </div>
  <script src="js/app.js"></script>
</body>

</html>

I have tried to calculate it and hard code it but it worked for a fixed width, but it didn't work if the screen was smaller.


Solution

  • It's commendable that you're writing the carousel element yourself. I see that you're using the CSS transform property to shift the elements from their original positions. If you calculate with better values here, your element will be centered.

    // Changed 75 / 3 to 100 / 3
    slider.style.transform = `translateX(-${(currentIndex - 1) * (100 / 3)}%)`;
    

    An element needs to take up one-third of 100% (33.33 %), so you will shift it by exactly that amount (depending on the index of the element). The 75% here seems a bit unexplained to me as a starting value.

    const slider = document.querySelector('.flag-slider');
    const flags = document.querySelectorAll('.flag');
    let currentIndex = 2; // Middle flag
    
    function updateFlags() {
      flags.forEach((flag, index) => {
        flag.classList.remove('active');
        if (index === currentIndex - 1) {
          flag.classList.add('active');
        }
      });
    }
    
    function slideFlags() {
      // Slide to the left
      slider.style.transform = `translateX(-${(currentIndex - 1) * (100 / 3)}%)`;
    
      currentIndex++;
    
      if (currentIndex > flags.length) {
        console.log('reset');
        currentIndex = 2;
        slider.style.transform = `translateX(0%)`;
      }
    
      updateFlags();
    }
    
    // Initial flag setup
    updateFlags();
    
    // Auto-slide every 2 seconds
    setInterval(slideFlags, 2000);
    * {
      margin: 0;
      padding: 0;
      box-sizing: border-box;
    }
    
    body {
      font-family: Arial, sans-serif;
      background-color: #f0f0f0;
    }
    
    .countries {
      display: flex;
      flex-direction: column;
      justify-content: center;
      width: 300px;
      padding: 20px;
    }
    
    .slider-container {
      width: 100%;
      margin: 50px auto;
      overflow: hidden;
      position: relative;
    }
    
    .flag-slider {
      display: flex;
      transition: transform 0.5s ease-in-out;
    }
    
    .flag,
    .last_flag {
      width: 33.33%;
      padding: 10px;
      display: flex;
      justify-content: center;
      align-items: center;
      transition: transform 0.5s ease-in-out, opacity 0.5s ease-in-out;
    }
    
    .flag img {
      width: 100%;
      object-fit: contain;
    }
    
    .flag.active {
      transform: scale(1.2);
    }
    <div class="countries">
      <div class="slider-container">
        <div class="flag-slider">
          <img class="flag" src="https://picsum.photos/200?1" alt="Australia">
          <img class="flag" src="https://picsum.photos/200?2" alt="Austria">
          <img class="flag" src="https://picsum.photos/200?3" alt="Brazil">
          <img class="flag" src="https://picsum.photos/200?4" alt="Canada">
          <img class="flag" src="https://picsum.photos/200?5" alt="France">
          <img class="flag" src="https://picsum.photos/200?6" alt="Germany">
          <img class="flag" src="https://picsum.photos/200?7" alt="India">
          <img class="flag" src="https://picsum.photos/200?8" alt="Mexico">
          <img class="flag" src="https://picsum.photos/200?9" alt="Philippines">
          <img class="flag" src="https://picsum.photos/200?10" alt="South Africa">
          <img class="flag" src="https://picsum.photos/200?11" alt="Egypt">
          <img class="flag" src="https://picsum.photos/200?12" alt="UK">
          <img class="flag" src="https://picsum.photos/200?13" alt="USA">
          <img class="flag" src="https://picsum.photos/200?14" alt="Venezuela">
          <img class="flag" src="https://picsum.photos/200?15" alt="Australia">
          <img class="last_flag" src="https://picsum.photos/200?16" alt="Austria">
        </div>
      </div>
      <span>Different countries</span>
    </div>