Search code examples
javascripthtmlcssslider

I want to create a slide that goes behind other images


I know im stupid about this, but i cant simply figure out what is called or how to best approach this.

I want to create a slider that has one focus image in the middle and other images extrudes out in the sides. like presented in the image here enter image description here

And of course when you click left or right it should go in that direction.

My approach so far is to make inline-flex and then make 5 divs where in each are an image and the center one is larger etc. and so on outwards.

But im still curious on how to make this work the right way.


Solution

  • I have prepared an example that should meet all your conditions: swiping, scaling, prev/next buttons, click on card

    const gallery = document.querySelector('.gallery')
    const cardWrappers = document.querySelectorAll('.card-wrapper')
    const prevButton = document.querySelector('.prev-button')
    const nextButton = document.querySelector('.next-button')
    
    let selectedIndex = 2
    
    // move card position depend on selected index
    
    const applyCardPositions = () => {
      cardWrappers.forEach((cardWrapper, index) => {
        const workingIndex = selectedIndex <= 2
            ? index + (2 - selectedIndex)
          : index - selectedIndex + 2
        cardWrapper.dataset.index = index
        cardWrapper.dataset.position = Math.abs(index - selectedIndex)
        cardWrapper.style.left = `${ workingIndex * 20 }%`
      })
    }
    
    applyCardPositions()
    
    // helpers
    
    const decreaseSelectedIndex = () => {
      if (selectedIndex > 0) {
        selectedIndex -= 1
            applyCardPositions()
      }
    }
    
    const increaseSelectedIndex = () => {
      if (selectedIndex < cardWrappers.length - 1) {
        selectedIndex += 1
            applyCardPositions()
      }
    }
    
    // button events
    
    prevButton.addEventListener('click', decreaseSelectedIndex)
    nextButton.addEventListener('click', increaseSelectedIndex)
    
    // click on card
    
    cardWrappers.forEach(cardWrapper => {
        cardWrapper.addEventListener('click', (e) => {
        selectedIndex = parseInt(cardWrapper.dataset.index)
            applyCardPositions()
      })
    })
    
    // swipe events
    
    startPos = [0, 0]
    gallery.addEventListener('pointerdown', (e) => {
        startPos = [e.clientX, e.clientY]
    })
    
    gallery.addEventListener('pointerup', (e) => {
        const endPos = [e.clientX, e.clientY]
      
      // threshold
      if (Math.abs(endPos[0] - startPos[0]) < 50) {
        return
      }
      
      if (endPos[0] < startPos[0]) {
        increaseSelectedIndex()
      }
      
      if (endPos[0] > startPos[0]) {
        decreaseSelectedIndex()
      }
    })
    .gallery {
      position: relative;
      width: 100%;
      height: 240px;
      background: #eee;
      overflow: hidden;
    }
      
    .gallery .card-wrapper {
      position: absolute;
      top: 0;
      left: 0;
      width: 20%;
      height: 90%;
      top: 5%;
      transition: .5s ease-out;
    }
        
    .gallery .card {
      display: flex;
      align-items: center;
      justify-content: center;
      font-size: 30px;
      width: 90%;
      margin-left: 5%;
      height: 100%;;
      background: #ddd;
      user-select: none;
      transition: .5s ease-out;
    }
          
    .gallery [data-position="0"] .card {
      background: #aaa
    }
    
    .gallery [data-position="1"] .card {
      transform: scale3d(.9, .9, .9);
    }
    
    .gallery [data-position="2"] .card {
      transform: scale3d(.8, .8, .8);
    }
    
    .gallery [data-position="3"] .card {
      transform: scale3d(.7, .7, .7);
    }
    
    .prev-button,
    .next-button {
      display: flex;
      align-items: center;
      justify-content: center;
      position: absolute;
      background: #fff;
      color: #333;
      width: 30px;
      height: 30px;
      border-radius: 50%;
      cursor: pointer;
      left: 10px;
      top: calc(50% - 15px);
      user-select: none;
    }
    
    .next-button {
      left: auto;
      right: 10px;
      top: calc(50% - 15px);
    }
    <div class="gallery">
      <div class="card-wrapper">
        <div class="card">A</div>
      </div>
      <div class="card-wrapper">
        <div class="card">B</div>
      </div>
      <div class="card-wrapper">
        <div class="card">C</div>
      </div>
      <div class="card-wrapper">
        <div class="card">D</div>
      </div>
      <div class="card-wrapper">
        <div class="card">E</div>
      </div>
      <div class="card-wrapper">
        <div class="card">F</div>
      </div>
      
      <div class="prev-button">
        &lt;
      </div>
      
      <div class="next-button">
        &gt;
      </div>
    </div>