В предыдущей статье у нас получился красивый слайдер («карусель») с круговым вращением. А сегодня я создам слайдер, пролистывающий стопку «полароидных» снимков. Пока не смотрите код, сначала я должен вам многое про него рассказать. Поехали! К старту нашего курса по Fullstack-разработке на Python. Большую часть HTML и CSS для этого проекта я возьму из кода кругового слайдера из предыдущей статьи. HTML-разметка абсолютно та же: А ниже — исходный CSS родительского контейнера .gallery. Контейнер — это грид, где изображения находятся в стопке одно над другим: Пока ничего сложного. Для эффекта «полароидности» я использую свойства border и box-shadow. Попробуйте поиграть со стилями, возможно, вам удастся добиться большего! Я же приступлю к самому сложному — к анимации.  Логика слайдера основана на порядке размещения изображений в стопке. Да, мы будем работать с z-index. Сначала у всех картинок будет один и тот же z-index, равный 2. Так последнее изображение будет наверху стопки. Затем последняя картинка смещается вправо, пока не появится следующая. После z-index картинки уменьшается и она помещается обратно в стопку. Теперь её z-index меньше, чем у других изображений, и она перемещается вниз стопки.  Посмотрите на упрощённую демоверсию слайдера. Наведите мышь на изображение, чтобы увидеть анимацию. Так же нужно поступить с остальными картинками. Вот алгоритм с псевдоселектором :nth-child() для разных изображений: Бесконечный слайдер готов! В предыдущей статье я написал лишь одну анимацию и проигрывал её с различными задержками для каждого изображения. Здесь будет такой же подход. Для начала давайте представим временную шкалу анимации сначала для трёх картинок, а затем и для любого их числа (N).  Анимация разбита на три этапа — «смещение вправо», «смещение влево» и «стоп». Задержки между изображениями определяются так: если анимация первой картинки начинается в 0s (0 с), а её продолжительность — 6s (6 с), то анимация второй картинки начинается в -2s (минус 2 с), а третьей — -4s (минус 4 с). Также видно, что этап «стоп» занимает две трети времени всей анимации (2*100%/3), а «смещение вправо» и «смещение влево» в сумме занимают треть времени. Следовательно, длительность каждого смещения равна 100%/6 от времени всей анимации.  Ключевые кадры анимации выглядят так: 120% — произвольная цифра. Нужно значение больше 100%. Изображения должны смещаться вправо за пределы границ других картинок. Необходимо сместить изображения по крайней мере на 100% от их размера. Вот почему я выбрал число 120% — чтобы получить немного дополнительного места. Далее нужно прописать значения z-index. Помните, что необходимо обновлять z-indexкартинки после того, как она сместится вправо.  Вместо того чтобы определить одно состояние на точке временной линии, равной 16.67% (100%/6), определим два состояния почти в одной и той же точке (16.66 и 16.67%), где z-index уменьшается перед тем, как изображение смещается обратно в стопку. Вот что произойдёт после того, как мы соединим всё вместе. Странно, смещение работает нормально, но порядок изображений в стопке неправильный. Анимация начинается правильно, верхнее изображение перемещается назад… Но следующие изображения не следуют этому примеру. Обратите внимание на вторую картинку — она возвращается на верх стопки, а затем следующее фото появляется поверх неё. Давайте внимательно посмотрим на изменения z-index. Изначально у всех изображений z-index равен 2. Это значит, что порядок картинок в стопке выглядит так… Третья картинка смещается, её z-index обновляется. Теперь порядок картинок таков: То же самое делаем со второй картинкой: …и с первой: Вроде бы всё должно быть в порядке, но на самом деле нет! Когда первая картинка перемещается назад, третья начинает новую итерацию, что означает, что её z-index снова становится равным 2: На самом деле все изображения никогда не получали значение z-index, равное 2! Когда изображения неподвижны (к примеру, на этапе «стоп»), z-index равен 1. Если третье фото смещается, а его z-index изменяется с 2 до 1, оно остается поверх стопки! Если у всех изображений одинаковый `z-index, последнее в исходной последовательности — в данном случае третье — оказывается сверху. Смещение третьего изображения приводит к следующему: Третье изображение всё ещё поверх стопки, а следом наверх перемещается второе, когда его анимация перезапускается при z-index: 2: Когда оно смещается, получается вот что: А затем сверху оказывается первая картинка: Знаю, это сложно. Но наша логика отчасти правильна. Нужно немного изменить анимацию, и всё заработает. Фокус в том, чтобы верно сбросить значение z-index. Давайте вернёмся на этап, когда третье изображение находилось сверху стопки: После смещения третьей картинки и изменения её z-indexона остаётся сверху. Нам же необходимо обновить z-index второй картинки. Давайте перед смещением третьего изображения за пределы стопки сделаем z-index второго изображения равным 2. Другими словами, z-index второй картинки сбрасывается перед окончанием анимации.  Зелёный плюс означает увеличение z-index до 2, а красный минус — уменьшение до 1. Второе фото сначала имеет z-index, равный 2, а при смещении из стопки он уменьшается до 1. Но, прежде чем первое изображение смещается из стопки, сделаем z-index второго изображения равным 2. Таким образом, z-index первого и z-index второго изображения получаются одинаковыми. Но третье изображение всё равно окажется сверху, так как в DOM оно появляется позже. После смещения третьего фото и обновления его z-indexоно оказывается внизу стопки. Это происходит на двух третях анимации. Необходимо соответствующим образом обновить ключевые кадры: Уже лучше, но все ещё не совсем… Не беспокойтесь, нам не придётся снова менять ключевые кадры, ведь такая ситуация возникает, только если в анимации задействовано последнее фото. Можно создать «особую» анимацию ключевых кадров специально для решения проблемы последнего изображения. Когда первое фото находится сверху, происходит следующее: После предыдущего изменения третье изображение появится сверху перед смещением первого. Так происходит только сейчас, потому что следующее изображение, которое двигается после первого, — это последнее изображение, которое находится выше в DOM. Остальные фото работают, как нужно, потому что сначала идёт N, затем — N - 1, потом 3 меняется на 2, а 2 на 1… Но затем происходит переход от 1 к N. Избежим этого, используя следующие ключевые кадры для последнего изображения: z-index сбрасывается на 5/6 анимации (а не на 2/3), когда первое фото находится вне стопки. Больше никакого выпрыгивания картинки! Ура. Теперь всё работает безупречно! Вот окончательный код во всём его великолепии: Теперь, когда анимация правильно отображает три фотографии, давайте перепишем код так, чтобы он работал с любым числом (N) картинок. Но сначала оптимизируем и уберём избыточный код. Для этого разделяем анимацию: Теперь кода намного меньше! Я создал отдельную анимацию для смещения, а другую — для обновления z-index. Обратите внимание, что при анимации z-index используется steps(1). Я использую steps(1), потому что хочу резко изменить значение z-index, а не постепенно, как в анимации сдвига. Теперь код легче читать и поддерживать. Стало ясно, как работать с любым числом изображений. Необходимо обновлять задержки анимации и процентные значения ключевых кадров. С задержками всё просто — можно использовать цикл, который я написал в предыдущей статье для поддержки множества изображений в круговом слайдере: От ванильного CSS переходим к SASS. Затем представим, как временная шкала изменяется при наличии N количества изображений. Не стоит забывать, что анимация состоит из трёх этапов:  После «смещения вправо» и «смещения влево» изображение должно оставаться неподвижным, пока другие картинки не пройдут через анимации. Так что этап «стоп» должен длиться столько же, сколько и этапы (N − 1) «смещения вправо» и «смещения влево». В течение одной итерации «сместятся» N изображений. Таким образом, «смещение вправо» и «смещение влево» вместе длятся 100%/N от общего времени анимации. Изображение выходит из стопки в (100%/N)/2 и входит обратно в стопку в 100%/N. Этот код: заменяем на этот: Если заменить N на 3, получается 16.67 и 33.33%, если в стопке три фотографии. Применяя такую же логику для порядка наложения, получаем следующее: Нам всё ещё нужно обновить значение 66.33%. В этой точке сбрасывается z-index изображения перед окончанием анимации и одновременно следующее изображение начинает смещаться. Смещение занимает 100%/N, а сброс z-index происходит в 100% — 100%/N: Но для работы анимации z-order-last сброс z-index должен произойти чуть позже. Помните о фиксе для последней фотографии? Сброс z-index должен происходить, когда первая картинка находится вне стопки, а не когда она начинает смещение. Здесь используется схожий подход: Готово! Вот слайдер с пятью картинками: Для красоты добавим поворот: Я всего лишь добавил rotate(var(--r)) к свойству transform. В цикле --r — случайный угол: Поворот приводит к возникновению небольших глитчей. Иногда изображения перепрыгивают в конец стопки, но это не важно. Вся работа с z-index потребовала точной настройки. Если раньше вы не были уверены, как работает порядок наложения, то теперь, надеюсь, вы понимаете принцип его работы гораздо лучше! Если вам что-то показалось непонятным, настоятельно советую вам ещё раз прочитать эту статью и расписать всё на бумаге. Попробуйте проиллюстрировать каждый шаг анимации, используя разное количество изображений, чтобы лучше понять, как всё работает. В прошлой статье я показал несколько геометрических хитростей и создал закольцованный круговой слайдер. Сегодня — сделал что-то похожее с помощью z-index. В обоих случаях я не дублировал картинки для создания непрерывной анимации и не использовал JavaScript. А в следующей статье я покажу вам, как создать трёхмерный слайдер. Не переключайтесь!  Data Science и Machine Learning Python, веб-разработка Мобильная разработка Java и C# От основ — в глубину А также