skip to Main Content

I’m working on creating a panoramic 3D swiper carousel similar to the following design:
Required Output Image

However, my current implementation does not achieve the same effect, and the carousel looks like this instead:

enter image description here

I want to achieve that carousel in CSS
Here’s the CSS code that I’ve tried so far:

.coverflow-container {
  perspective: 1000px;
  width: 100%;
  height: 250px;
  position: relative;
  overflow: hidden;
}

.coverflow-item {
  position: absolute;
  width: 200px; /* Width of each slide */
  height: 250px; /* Height of non-active slides */
  left: 50%;
  transform-origin: center;
  transition: transform 0.5s ease, z-index 0s linear, height 0.5s ease;
  display: flex;
  justify-content: center;
  align-items: center;
  background: #b5b4b6;
  color: white;
  border: 1px solid black;
  box-sizing: border-box;
  opacity: 0.7;
}

.coverflow-item.active {
  background: #272a36;
  z-index: 3;
  opacity: 1;
  height: 90%; /* Larger height for the active slide */
}

.coverflow-controls {
  position: absolute;
  width: 100%;
  bottom: 10px;
  text-align: center;
  padding-top: 100px;
}

button {
  padding: 10px;
  margin: 0 10px;
  font-size: 16px;
  cursor: pointer;
}

And here’s a link to my CodeSandbox: https://codesandbox.io/s/coverflow-swiper-5kywvv?file=/src/App.css
I tried tweaking CSS to achieve that effect. But I am unable to get the same like that in the UI.

I want my carousel to be like this
enter image description here

Could anyone help me on how to adjust my CSS to achieve the desired effect?

2

Answers


  1. I will correct your initial solution, to continue work on your direction.

    1. I would place tiles into a flex container instead of using position: absolute. Make.coverflow-container as a flex. Then, you don’t have to apply horisontal transition to each element. Instead, you can do the shift to the whole container when active tile changes.
    2. I would recommend instead of using scale, applying transformZ on each tile. Since you are using perspective on the tiles container, we could use its advantage here on tiles, to shift them back from the front. The closer a tile to the center, the far it by Z axis.
    3. For more gentle effect, I would also do rotateY on each element progressively – the far a tile from the center, the bigger rotation on Y axis. Also, the more a tile rotated, the more it «shrinks», so we need to move it close to the center. For that we use translateX.
    4. Keep in mind, that the order in transform matters. So we first move a tile on its place, and then rotate.

    Here are the main changes I made.

    const TILE_SIZE = 150;
    
    /* the closer we to the center, the more far we move the tile */
    function calcTranslateZ(index, activeIndex) {
        if (index === activeIndex) return -TILE_SIZE * 2.5;
        return -(TILE_SIZE*10 / (Math.abs(index - activeIndex) * slides.length));
    }
    
    /* the more you far from center, the smaller the gap */
    function calcTranslateX(index, activeIndex) {
      if (index === activeIndex) return 0;
      return Math.pow(activeIndex - index, 3) * 10;
    }
    
    /* the closer to the center, the more "exposed the tile" */
    function calcRotateY(index, activeIndex) {
      return (activeIndex - index) * 30;
    }
    
    /* we shif the container  with the tiles, so the active tile is centralized */
    function calcShift(activeIndex) {
      return ((slides.length - 1) / 2 - activeIndex) * TILE_SIZE;
    }
    
    /* if a tile far from center, it looks ugly */
    function shouldHideTile(index, activeIndex) {
      return Math.abs(activeIndex - index) > 2;
    }
      
    ....
      
    // and on the template side
    return (
        <>
          <div
            className="coverflow-container"
            style={{
              transform: `translateX(${calcShift(activeIndex)}px)`
            }}
          >
            {slides.map((slide, index) => {
              return (
                <div
                  key={slide}
                  className={`
                    coverflow-item ${
                       index === activeIndex ? "active" : ""
                    }
                    ${shouldHideTile(index, activeIndex) ? "hidden" : ""}
                  `}
                  style={{
                    transform: `
                      translateZ(${calcTranslateZ(index, activeIndex)}px)
                      translateX(${calcTranslateX(index, activeIndex)}px)
                      rotateY(${calcRotateY(index, activeIndex)}deg) `
                  }}
                  onClick={() => slideTo(index)}
                >
                  {slide}
                </div>
              );
            })}
          </div>
          
       ....
       </>
    
    

    The full solution is here

    The solution will look like that:
    enter image description here

    Login or Signup to reply.
  2. Duplicate of: How to get this curve effect using css with reactjs?

    Snipped is fully from @imhvost code in link above

    <!DOCTYPE html>
    <html lang="en">
    
    <head>
      <meta charset="utf-8" />
      <title>Swiper demo</title>
      <meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1" />
      <!-- Link Swiper's CSS -->
      <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/swiper@8/swiper-bundle.min.css" />
    
      <!-- Demo styles -->
      <style>
        html,
        body {
          position: relative;
          height: 100%;
        }
    
        body {
          background: #eee;
          font-family: Helvetica Neue, Helvetica, Arial, sans-serif;
          font-size: 14px;
          color: #000;
          margin: 0;
          padding: 0;
        }
    
        .swiper {
          width: 100%;
          padding-top: 50px;
          padding-bottom: 50px;
        }
    
        .swiper-slide {
          background-position: center;
          background-size: cover;
          width: 100px;
          height: 100px;
        }
    
        .swiper-slide img {
          display: block;
          width: 100%;
          height: 100%;
          object-fit: cover;
        }
      </style>
    </head>
    
    <body>
      <!-- Swiper -->
      <div class="swiper mySwiper">
        <div class="swiper-wrapper">
          <div class="swiper-slide">
            <img src="https://swiperjs.com/demos/images/nature-1.jpg" />
          </div>
          <div class="swiper-slide">
            <img src="https://swiperjs.com/demos/images/nature-2.jpg" />
          </div>
          <div class="swiper-slide">
            <img src="https://swiperjs.com/demos/images/nature-3.jpg" />
          </div>
          <div class="swiper-slide">
            <img src="https://swiperjs.com/demos/images/nature-4.jpg" />
          </div>
          <div class="swiper-slide">
            <img src="https://swiperjs.com/demos/images/nature-5.jpg" />
          </div>
          <div class="swiper-slide">
            <img src="https://swiperjs.com/demos/images/nature-6.jpg" />
          </div>
          <div class="swiper-slide">
            <img src="https://swiperjs.com/demos/images/nature-7.jpg" />
          </div>
          <div class="swiper-slide">
            <img src="https://swiperjs.com/demos/images/nature-8.jpg" />
          </div>
          <div class="swiper-slide">
            <img src="https://swiperjs.com/demos/images/nature-9.jpg" />
          </div>
        </div>
        <div class="swiper-pagination"></div>
      </div>
    
      <!-- Swiper JS -->
      <script src="https://cdn.jsdelivr.net/npm/swiper@8/swiper-bundle.min.js"></script>
    
      <!-- Initialize Swiper -->
      <script>
        var swiper = new Swiper(".mySwiper", {
          effect: "coverflow",
          grabCursor: true,
          centeredSlides: true,
          slidesPerView: "auto",
          spaceBetween: 10,
          loop: true,
          loopedSlides: 8,
          coverflowEffect: {
            rotate: 80,
            depth: -100,
            modifier: .2,
            scale: 1.2,
          },
          pagination: {
            el: ".swiper-pagination",
            clickable: true,
          },
        });
      </script>
    </body>
    
    </html>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search