CSS Бесконечный и круговой вращающийся слайдер изображений PlatoBlockchain Data Intelligence. Вертикальный поиск. Ай.

CSS бесконечный и круговой вращающийся слайдер изображений

Слайдеры изображений (также называемые каруселями) есть везде. Есть множество приемов CSS для создания обычного слайдера где изображения скользят слева направо (или наоборот). То же самое с множество библиотек JavaScript которые создают причудливые слайдеры со сложной анимацией. Мы не собираемся делать ничего из этого в этом посте.

В небольшой серии статей мы собираемся исследовать некоторые причудливые и необычные слайдеры, созданные только на CSS. Если вы устали видеть одни и те же классические слайдеры, то вы попали по адресу!

Серия слайдеров CSS

В этой первой статье мы начнем с того, что я называю «круговой вращающийся слайдер изображений»:

Круто, да? давайте разберем код!

Разметка HTML

Если вы следили за моей серией причудливые украшения для изображений or Сетка CSS и пользовательские формы, то вы знаете, что мое первое правило — работать с наименьшим возможным HTML-кодом. Я всегда изо всех сил стараюсь найти решения CSS, прежде чем загромождать свой код большим количеством

с и прочее.

Здесь действует то же правило — наш код — это не что иное, как список изображений в контейнере.

Допустим, мы работаем с четырьмя изображениями:

Вот и все! Теперь давайте перейдем к интересной части кода. Но сначала мы углубимся в это, чтобы понять логику работы нашего слайдера.

Как это работает?

Вот видео где я удаляю overflow: hidden из CSS, чтобы мы могли лучше понять, как движутся изображения:

Как будто наши четыре изображения размещены на большом круге, который вращается против часовой стрелки.

CSS бесконечный и круговой вращающийся слайдер изображений

Все изображения имеют одинаковый размер (обозначается S на рисунке). Обратите внимание на синий круг, который представляет собой круг, пересекающийся с центром всех изображений и имеющий радиус (R). Это значение понадобится нам позже для нашей анимации. R равно 0.707 * S. (Я пропущу геометрию, которая дает нам это уравнение.)

Давайте напишем немного CSS!

Мы будем использовать CSS-сетка чтобы разместить все изображения в одной области друг над другом:

.gallery  {
  --s: 280px; /* control the size */

  display: grid;
  width: var(--s);
  aspect-ratio: 1;
  padding: calc(var(--s) / 20); /* we will see the utility of this later */
  border-radius: 50%;
}
.gallery > img {
  grid-area: 1 / 1;
  width: 100%;
  height: 100%;
  object-fit: cover;
  border-radius: inherit;
}

Пока ничего сложного. Самая сложная часть — это анимация.

Мы говорили о вращении большого круга, но на самом деле мы будем вращать каждое изображение отдельно, создавая иллюзию большого вращающегося круга. Итак, давайте определим анимацию, mи примените его к элементам изображения:

.gallery > img {
  /* same as before */
  animation: m 8s infinite linear;
  transform-origin: 50% 120.7%;
}

@keyframes m {
  100% { transform: rotate(-360deg); }
}

Основной трюк основан на этой выделенной строке. По умолчанию CSS transform-origin свойство равно center (или 50% 50%), который заставляет изображение вращаться вокруг своего центра, но нам это не нужно. Нам нужно, чтобы изображение вращалось вокруг центра большой круг который содержит наши изображения, следовательно, новое значение для transform-origin.

Так как R равно 0.707 * Sмы можем сказать, что R равно 70.7% размера изображения. Вот рисунок, иллюстрирующий, как мы получили 120.7% значение:

CSS Бесконечный и круговой вращающийся слайдер изображений PlatoBlockchain Data Intelligence. Вертикальный поиск. Ай.
CSS бесконечный и круговой вращающийся слайдер изображений

Давайте запустим анимацию и посмотрим, что произойдет:

Я знаю я знаю. Результат далек от того, что мы хотим, но на самом деле мы очень близки. Может показаться, что там всего одно изображение, но не забывайте, что мы расположили все изображения друг над другом. Все они вращаются одновременно, и видно только верхнее изображение. Что нам нужно, так это задержать анимацию каждого изображения, чтобы избежать этого наложения.

.gallery > img:nth-child(2) { animation-delay: -2s; } /* -1 * 8s / 4 */
.gallery > img:nth-child(3) { animation-delay: -4s; } /* -2 * 8s / 4 */
.gallery > img:nth-child(4) { animation-delay: -6s; } /* -3 * 8s / 4 */

Дела уже идут лучше!

Если мы скроем переполнение в контейнере, мы уже можем видеть ползунок, но мы немного обновим анимацию, чтобы каждое изображение оставалось видимым в течение короткого периода времени, прежде чем двигаться дальше.

Мы собираемся обновить ключевые кадры анимации, чтобы сделать именно это:

@keyframes m {
  0%, 3% { transform: rotate(0); }
  22%, 27% { transform: rotate(-90deg); }
  47%, 52% { transform: rotate(-180deg); }
  72%, 77% { transform: rotate(-270deg); }
  98%, 100% { transform: rotate(-360deg); }
}

Для каждого 90deg (360deg/4, Где 4 это количество изображений) мы добавим небольшую паузу. Каждое изображение будет оставаться видимым в течение 5% общей продолжительности, прежде чем мы перейдем к следующему (27%-22%, 52%-47%, так далее.). Я собираюсь обновить animation-timing-function использование cubic-bezier() функция, чтобы сделать анимацию немного красивее:

Теперь наш слайдер идеален! Что ж, почти идеально, потому что нам все еще не хватает последнего штриха: красочной круглой рамки, которая вращается вокруг наших изображений. Мы можем использовать псевдоэлемент на .gallery обертка, чтобы сделать это:

.gallery {
  padding: calc(var(--s) / 20); /* the padding is needed here */
  position: relative;
}
.gallery::after {
  content: "";
  position: absolute;
  inset: 0;
  padding: inherit; /* Inherits the same padding */
  border-radius: 50%;
  background: repeating-conic-gradient(#789048 0 30deg, #DFBA69 0 60deg);
  mask: 
    linear-gradient(#fff 0 0) content-box, 
    linear-gradient(#fff 0 0);
  mask-composite: exclude;
}
.gallery::after,
.gallery >img {
  animation: m 8s infinite cubic-bezier(.5, -0.2, .5, 1.2);
}

Я создал круг с повторяющийся конический градиент для фона при использовании трюк с маскировкой это показывает только заполненную область. Затем я применяю к нему ту же анимацию, которую мы определили для изображений.

Мы сделали! У нас есть крутой круглый слайдер:

Добавим больше изображений

Работа с четырьмя изображениями — это хорошо, но было бы лучше, если бы мы могли масштабировать ее на любое количество изображений. В конце концов, это цель слайдера изображений. Мы должны быть в состоянии рассмотреть N изображениями.

Для этого мы собираемся сделать код более универсальным, представив Sass. Во-первых, мы определяем переменную для количества изображений ($n), и мы обновим каждую часть, где мы жестко запрограммировали количество изображений (4).

Начнем с задержек:

.gallery > img:nth-child(2) { animation-delay: -2s; } /* -1 * 8s / 4 */
.gallery > img:nth-child(3) { animation-delay: -4s; } /* -2 * 8s / 4 */
.gallery > img:nth-child(4) { animation-delay: -6s; } /* -3 * 8s / 4 */

Формула задержки такова. (1 - $i)*duration/$n, что дает нам следующий цикл Sass:

@for $i from 2 to ($n + 1) {
  .gallery > img:nth-child(#{$i}) {
    animation-delay: calc(#{(1 - $i) / $n} * 8s);
  }
}

Мы также можем сделать продолжительность переменной, если мы действительно этого хотим. Но давайте перейдем к анимации:

@keyframes m {
  0%, 3% { transform: rotate(0); }
  22%, 27% { transform: rotate(-90deg); }
  47%, 52% { transform: rotate(-180deg); }
  72%, 77% { transform: rotate(-270deg); }
  98%, 100% {transform: rotate(-360deg); }
}

Давайте упростим его, чтобы получить лучшее представление о шаблоне:

@keyframes m {
  0% { transform: rotate(0); }
  25% { transform: rotate(-90deg); }
  50% { transform: rotate(-180deg); }
  75% { transform: rotate(-270deg); }
  100% { transform: rotate(-360deg); }
}

Шаг между каждым состоянием равен 25% - который 100%/4 — и добавляем -90deg угол - это -360deg/4. Это означает, что вместо этого мы можем написать наш цикл следующим образом:

@keyframes m {
  0% { transform: rotate(0); }
  @for $i from 1 to $n {
    #{($i / $n) * 100}% { transform: rotate(#{($i / $n) * -360}deg); }  
  }
  100% { transform: rotate(-360deg); }
}

Поскольку каждое изображение занимает 5% анимации, мы меняем это:

#{($i / $n) * 100}%

…с этим:

#{($i / $n) * 100 - 2}%, #{($i / $n) * 100 + 3}%

Следует отметить, что 5% — произвольное значение, которое я выбираю для этого примера. Мы также можем сделать его переменной, чтобы контролировать, сколько времени каждое изображение должно оставаться видимым. Я пропущу это для простоты, но в качестве домашнего задания вы можете попробовать сделать это и поделиться своей реализацией в комментариях!

@keyframes m {
  0%,3% { transform: rotate(0); }
  @for $i from 1 to $n {
    #{($i / $n) * 100 - 2}%, #{($i / $n) * 100 + 3}% { transform: rotate(#{($i / $n) * -360}deg); }  
  }
  98%,100% { transform: rotate(-360deg); }
}

Последний бит - обновить transform-origin. Нам понадобятся некоторые приемы геометрии. Каким бы ни было количество изображений, конфигурация всегда одинакова. У нас есть наши изображения (маленькие круги), помещенные внутри большого круга, и нам нужно найти значение радиуса, R.

CSS Бесконечный и круговой вращающийся слайдер изображений PlatoBlockchain Data Intelligence. Вертикальный поиск. Ай.
CSS бесконечный и круговой вращающийся слайдер изображений

Вы, вероятно, не хотите скучного объяснения геометрии, поэтому вот как мы находим R:

R = S / (2 * sin(180deg / N))

Если мы выразим это в процентах, это даст нам:

R = 100% / (2 * sin(180deg / N)) = 50% / sin(180deg / N)

… что означает transform-origin значение равно:

transform-origin: 50% (50% / math.sin(180deg / $n) + 50%);

Были сделаны! У нас есть слайдер, который работает с любым количеством изображений!

Давайте добавим туда девять изображений:

Добавьте столько изображений, сколько хотите, и обновите $n переменная с общим количеством изображений.

Подведение итогов

Применив несколько приемов с использованием CSS-преобразований и стандартной геометрии, мы создали красивый круглый слайдер, не требующий большого количества кода. Что хорошо в этом ползунке, так это то, что нам не нужно дублировать изображения, чтобы сохранить бесконечную анимацию, поскольку у нас есть круг. После полного поворота мы вернемся к первому изображению!

Отметка времени:

Больше от CSS хитрости