Слайдер с отзывами

Я пока учусь, и ещё плохо знаю js, нужно реализовать вот такой свайпер, как на фото. введите сюда описание изображения Есть задумка (просьба не смеяться, это лишь моя догадка) Если взять Swiper pagination dynamic, и дальше вопрос - могу я вместо точек сделать там изображения? Да так, чтоб они были разные, и ткнув к примеру на самую крайнюю фото, чтоб у меня в слайдере появлялось такое же фото с отзывом. И как мне их сделать полумесяцем а не в одну строку?


Ответы (2 шт):

Автор решения: Yaonkey

В целом, задумка с Swiper интересная и имеет место быть, но, мне кажется, Flickity подойдет для этих целей больше, если использовать карусель. Единственное, это нужно грамотно стилизовать при помощи CSS.

То есть HTML-вид будет таким:

<div class="carousel">
  <div class="carousel-cell"><img src="image1.jpg" alt="Image 1"></div>
  <div class="carousel-cell"><img src="image2.jpg" alt="Image 2"></div>
  <div class="carousel-cell"><img src="image3.jpg" alt="Image 3"></div>
</div>

CSS будет таким:

    .carousel {
  width: 100%;
  height: 300px; /* Установите нужную высоту */
  overflow: hidden;
  position: relative;
}

.carousel-cell {
  width: 200px; /* Установите ширину ячейки */
  height: 100%;
  position: absolute;
  bottom: 0; /* Выравнивание по нижнему краю */
  transition: transform 0.5s ease;
}

.carousel-cell img {
  width: 100%;
  height: auto;
  border-radius: 50%; /* Закругление углов для полумесяца */
}

.carousel-cell:nth-child(1) { transform: translateX(-50%); }
.carousel-cell:nth-child(2) { transform: translateX(0); }
.carousel-cell:nth-child(3) { transform: translateX(50%); }

/* Процент поворота вручную нужно считать в зависимости от кол-ва изображений */

Ну и сам JS с подключением Flickity:

<script src="https://unpkg.com/flickity@2/dist/flickity.pkgd.min.js"></script>
<script>
  var flkty = new Flickity('.carousel', {
    // Опции Flickity
    cellAlign: 'left',
    contain: true,
    wrapAround: true,
    autoPlay: true
  });
</script>
→ Ссылка
Автор решения: UModeL

... могу я вместо точек сделать там изображения?

Да. В документации довольно подробно описана стилизация.

И как мне их сделать полумесяцем а не в одну строку?

Чтобы не заморачиваться с позиционирование, можно воспользоваться таким css-свойством, как offset и расположить кнопки вдоль пути с необходимой траекторией.

let resps = [{ avatar: 'avatar_man_dutch.jpg', name: 'Голландец', desc: '' }, { avatar: 'avatar_woman_algerian.jpg', name: 'Алжирка', desc: '' }, { avatar: 'avatar_man_kenyan.jpg', name: 'Кениец', desc: '' }, { avatar: 'avatar_woman_australian.jpg', name: 'Австралийка', desc: '' }, { avatar: 'avatar_man_korean.jpg', name: 'Кореец', desc: '' }, { avatar: 'avatar_woman_brazilian.jpg', name: 'Бразильянка', desc: '' }, { avatar: 'avatar_man_mexican.jpg', name: 'Мексиканец', desc: '' }, { avatar: 'avatar_woman_irish.jpg', name: 'Ирландка', desc: '' }, { avatar: 'avatar_man_turkish.jpg', name: 'Турок', desc: '' }, { avatar: 'avatar_woman_russian.jpg', name: 'Русская', desc: '' }];

let swiperWrapper = document.querySelector('.swiper-wrapper');
let swiperWrapperTemplate = swiperWrapper.querySelector('.swiper-slide-template');
let swiperBulletImages = ``;
resps.forEach((resp, index) => {
  let newSlide = swiperWrapperTemplate.content.cloneNode(true);
  let src = `https://umodel.narod.ru/shareweb/image/avatars/${resp.avatar}`;
  newSlide.querySelector('.avatar').src = src;
  newSlide.querySelector('.name').textContent = resp.name;
  swiperBulletImages += `
  div.swiper-pagination span.swiper-pagination-bullet:nth-of-type(${index + 1}) {
    background-image: url('${src}');
    offset-distance: ${(100 / (resps.length - 1)) * index}%;
  }
  `;
  newSlide.querySelector('.text').textContent = resp.desc || 'Lorem, ipsum dolor sit amet consectetur adipisicing elit. Corporis quibusdam inventore voluptatem, fugiat harum fuga sapiente error id aspernatur ea consectetur incidunt assumenda ipsa, tenetur iure voluptas velit ipsum laboriosam.';
  swiperWrapper.append(newSlide);
});

// Initial Swiper
const swiper = new Swiper('.swiper', {
  loop: true, pagination: { el: '.swiper-pagination', clickable: true }
});

document.head.appendChild(document.createElement('style')).textContent = swiperBulletImages;
.swiper {
  height: 600px; width: 600px;
  box-shadow: 0 0 2px #000;
}

/* Slide */
.swiper-slide {
  display: flex;
  flex-flow: column nowrap;
  justify-content: center;
  align-items: center;
  height: 600px; width: 600px;
  box-shadow: 0 0 2px #0000;
  user-select: none;
}

/* Content */
.swiper-slide p {
  height: 400px; width: 400px;
  border-radius: 50%;
  text-align: justify; text-align-last: center;
  word-spacing: -0.5px;
  overflow: hidden;
}

.shape-rounded { display: contents; }
.shape-rounded::before,
.shape-rounded::after {
  content: "";
  float: left;
  height: 100%; width: 50%;
  shape-outside: radial-gradient(farthest-side at 100%, transparent 100%, red);
  shape-margin: 1em;
}
.shape-rounded::after {
  float: right;
  shape-outside: radial-gradient(farthest-side at 0, transparent 100%, red);
}

.swiper-slide img.avatar {
  display: inline-block;
  height: 150px; width: 150px;
  border-radius: 50%;
  object-fit: contain;
}

.swiper-slide span.name {
  display: inline-block;
  padding: 1em;
  font: bold 24px/1em sans-serif;
}

.swiper-slide span.text {
  font: 14px/1em sans-serif;
  text-overflow: ellipsis;
  overflow: hidden;
}

/* Bullets */
.swiper-pagination {
  bottom: 0 !important;
  height: 200px; width: 100% !important;
  background-color: #fc00;
  pointer-events: none;
}

div.swiper-pagination span.swiper-pagination-bullet {
  margin: 0 -20px !important;
  height: 32px; width: 32px;
  offset: path('M -220 40, q 235 200 470 0') 0deg;
  opacity: 1;
  background-size: cover;
  box-shadow: 0 0 8px 12px #fff;
  transition: 0.3s transform, 0.3s margin;
  pointer-events: auto;
}
div.swiper-pagination span.swiper-pagination-bullet.swiper-pagination-bullet-active {
  margin: 0 !important;
  transform: scale(2);
  box-shadow: 0 0 1px 4px #fc8, 0 0 1px 8px #fc86;
}
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/swiper@8/swiper-bundle.min.css" />
<script src="https://cdn.jsdelivr.net/npm/swiper@8/swiper-bundle.min.js"></script>

<div class="swiper">
  <div class="swiper-wrapper">
    <!-- Slides -->
    <template class="swiper-slide-template">
      <div class="swiper-slide">
        <p><span class="shape-rounded"></span><img class="avatar"><span class="name"></span><br><span class="text"></span></p>
      </div>
    </template>
  </div>

  <div class="swiper-pagination"></div>
</div>

→ Ссылка