CSS Infinite Slider, що гортає зображення Polaroid PlatoBlockchain Data Intelligence. Вертикальний пошук. Ai.

CSS Infinite Slider гортає зображення Polaroid

В останній статті, ми створили гарний маленький повзунок (або «карусель», якщо вам це подобається), який обертається по колу. Цього разу ми збираємося зробити таку, яка гортає стопку зображень Polaroid.

Круто правда? Поки що не дивіться на код, тому що потрібно багато чого розгадати. Приєднуйтесь до мене, чи не так?

Серія слайдерів CSS

Основне налаштування

Більшість HTML і CSS для цього слайдера схожі на круговий, який ми створили минулого разу. Насправді ми використовуємо ту саму розмітку:

І це базовий CSS, який встановлює наш батько .gallery контейнер як сітка, де всі зображення розташовані одне на одному:

.gallery  {
  display: grid;
  width: 220px; /* controls the size */
}
.gallery > img {
  grid-area: 1 / 1;
  width: 100%;
  aspect-ratio: 1;
  object-fit: cover;
  border: 10px solid #f2f2f2;
  box-shadow: 0 0 4px #0007;
}

Поки нічого складного. Навіть для зображень у стилі Polaroid я використовую лише деякі border та box-shadow. Можливо, ви зможете зробити це краще, тому сміливо пограйте з цими декоративними стилями! Ми зосередимося найбільше на анімації, яка є найскладнішою частиною.

У чому фокус?

Логіка цього повзунка залежить від порядку укладання зображень — так, ми збираємося пограти з z-index. Усі зображення починаються з одного z-index значення (2), що логічно буде останнє зображення на вершині стека.

Ми беремо це останнє зображення та пересуваємо його праворуч, доки воно не відкриє наступне зображення в стосі. Потім ми зменшуємо зображення z-index значення, то ми повертаємо його в колоду. І оскільки його z-index менше, ніж у решти зображень, воно стає останнім зображенням у стеку.

Ось демо-версія, яка демонструє трюк. Наведіть курсор на зображення, щоб активувати анімацію:

А тепер уявіть той самий трюк, застосований до всіх зображень. Ось шаблон, якщо ми використовуємо :nth-child() псевдоселектор для розрізнення зображень:

  • Пересуваємо останнє зображення (N). Видно наступне зображення (N - 1).
  • Пересуваємо наступне зображення (N - 1). Видно наступне зображення (N - 2)
  • Пересуваємо наступне зображення (N - 2). Видно наступне зображення (N - 3)
  • (Ми продовжуємо той самий процес, поки не дійдемо до першого зображення)
  • Пересуваємо перше зображення (1). Останнє зображення (N) знову видно.

Це наш нескінченний слайдер!

Розбір анімації

Якщо ви пам’ятаєте попередню статтю, я визначив лише одну анімацію та використовував затримки, щоб контролювати кожне зображення. Ми будемо робити те саме тут. Давайте спочатку спробуємо візуалізувати часову шкалу нашої анімації. Ми почнемо з трьох зображень, а потім узагальнимо їх для будь-якої кількості (N) зображень.

CSS Infinite Slider гортає зображення Polaroid

Наша анімація поділена на три частини: «ковзай праворуч», «ковзай ліворуч» і «не рухайся». Ми можемо легко визначити затримку між кожним зображенням. Якщо врахувати, що перше зображення починається з 0s, а тривалість дорівнює 6s, то другий розпочнеться о -2s а третій на -4s.

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

Ми також бачимо, що частина «не рухайся» займає дві третини всієї анімації (2*100%/3), тоді як частини «ковзання праворуч» і «ковзання ліворуч» займають одну третину разом — отже, кожна з них дорівнює 100%/6 загальної анімації.

Ми можемо написати наші ключові кадри анімації так:

@keyframes slide {
  0%     { transform: translateX(0%); }
  16.67% { transform: translateX(120%); }
  33.34% { transform: translateX(0%); }
  100%   { transform: translateX(0%); } 
}

Що 120% є довільним значенням. Мені потрібно було щось більше, ніж 100%. Зображення мають переміститися праворуч від решти зображень. Для цього йому потрібно як мінімум проїхати 100% його розміру. Ось чому я пішов 120% — отримати додатковий простір.

Тепер нам потрібно розглянути z-index. Не забувайте, що нам потрібно оновити зображення z-index значення після вона ковзає праворуч від купи, і перед тим ми повертаємо його на дно купи.

@keyframes slide {
  0%     { transform: translateX(0%);   z-index: 2; }
  16.66% { transform: translateX(120%); z-index: 2; }
  16.67% { transform: translateX(120%); z-index: 1; } /* we update the z-order here */
  33.34% { transform: translateX(0%);   z-index: 1; }
  100%   { transform: translateX(0% );  z-index: 1; }  
}

Замість визначення однієї держави на 16.67% (100%/6) точки на часовій шкалі, ми визначаємо два стани в майже ідентичних точках (16.66% та 16.67%) де z-index значення зменшується, перш ніж ми посунемо зображення назад на колоду.

Ось що відбувається, коли ми все це об’єднуємо:

Хммм, ковзаюча частина, здається, працює добре, але порядок укладання спотворений! Анімація починається добре, оскільки верхнє зображення переміщується назад… але наступні зображення не наслідують його приклад. Якщо ви помітили, друге зображення в послідовності повертається на вершину стека, перш ніж наступне зображення блимає поверх нього.

Треба уважно стежити за z-index зміни. Спочатку всі зображення є z-index: 2. Це означає, що порядок укладання має бути…

Our eyes 👀 --> 3rd (2) | 2nd (2) | 1st (2)

Пересуваємо третє зображення та оновлюємо його z-index щоб отримати це замовлення:

Our eyes 👀 --> 2nd (2) | 1st (2) | 3rd (1)

Те ж саме робимо з другим:

Our eyes 👀 --> 1st (2) | 3rd (1) | 2nd (1)

…і перший:

Our eyes 👀 --> 3rd (1) | 2nd (1) | 1st (1)

Ми це робимо, і ніби все добре. Але насправді це не так! Коли перше зображення переміщується назад, третє зображення починає ще одну ітерацію, тобто повертається z-index: 2:

Our eyes 👀 --> 3rd (2) | 2nd (1) | 1st (1)

Отже, насправді ми ніколи не мали всіх зображень z-index: 2 зовсім! Коли зображення не рухаються (тобто частина анімації «не рухається»), z-index is 1. Якщо ми пересунемо третє зображення та оновимо його z-index значення від 2 до 1, він залишиться на вершині! Коли всі зображення однакові z-index, останнє у вихідному порядку — наше третє зображення в цьому випадку — знаходиться на вершині стеку. Переміщення третього зображення призводить до наступного:

Our eyes 👀 --> 3rd (1) | 2nd (1) | 1st (1)

Третє зображення все ще знаходиться вгорі, і одразу після нього ми переміщуємо друге зображення вгору, коли його анімація перезапускається о z-index: 2:

Our eyes 👀 --> 2nd (2) | 3rd (1) | 1st (1)

Після того, як ми посунемо його, ми отримаємо:

Our eyes 👀 --> 3rd (1) | 2nd (1) | 1st (1)

Тоді перше зображення перескочить зверху:

Our eyes 👀 --> 1st(2) | 3rd (1) | 2nd (1)

Добре, я заблукав. Тоді вся логіка неправильна?

Я знаю, це бентежить. Але наша логіка не зовсім хибна. Нам потрібно лише трохи виправити анімацію, щоб усе працювало так, як ми хочемо. Хитрість полягає в тому, щоб правильно скинути z-index.

Давайте візьмемо ситуацію, коли третє зображення знаходиться вгорі:

Our eyes 👀 -->  3rd (2) | 2nd (1) | 1st (1)

Ми побачили, що третє зображення пересувається та змінюється z-index тримає його на вершині. Що нам потрібно зробити, це оновити z-index другого зображення. Отже, перш ніж відсунути третє зображення з колоди, ми оновимо z-index другого зображення до 2.

Іншими словами, ми скидаємо z-index другого зображення до завершення анімації.

Діаграма частин анімації з індикаторами збільшення або зменшення z-індексу.
CSS Infinite Slider гортає зображення Polaroid

Зелений символ плюса означає збільшення z-index до 2, а червоний символ мінуса відповідає z-index: 1. Друге зображення починається з z-index: 2, потім ми оновлюємо його до 1 коли він зісковзує з палуби. Але перш ніж перше зображення зійде з колоди, ми змінюємо z-index другого зображення назад до 2. Це переконається, що обидва зображення мають однакові z-index, але все одно третій залишиться вгорі, оскільки він з’являється пізніше в DOM. Але після третього зображення слайдів і його z-index оновлюється, він переміщається вниз.

Це дві третини анімації, тому давайте відповідно оновимо ключові кадри:

@keyframes slide {
  0%     { transform: translateX(0%);   z-index: 2; }
  16.66% { transform: translateX(120%); z-index: 2; }
  16.67% { transform: translateX(120%); z-index: 1; } /* we update the z-order here */
  33.34% { transform: translateX(0%);   z-index: 1; }
  66.33% { transform: translateX(0%);   z-index: 1; }
  66.34% { transform: translateX(0%);   z-index: 2; } /* and also here */
  100%   { transform: translateX(0%);   z-index: 2; }  
}

Трохи краще, але все одно ні досить там. Є ще одна проблема…

О ні, це ніколи не закінчиться!

Не хвилюйтеся, ми не збираємося знову змінювати ключові кадри, оскільки ця проблема виникає лише тоді, коли задіяно останнє зображення. Ми можемо створити «спеціальну» анімацію ключових кадрів спеціально для останнього зображення, щоб виправити ситуацію.

Коли перше зображення знаходиться вгорі, ми маємо наступну ситуацію:

Our eyes 👀 -->  1st (2) | 3rd (1) | 2nd (1)

Враховуючи попередні налаштування, які ми зробили, третє зображення перескочить у верхній частині перед тим, як перше зображення з’явиться. Це відбувається лише в цій ситуації, оскільки наступне зображення, яке переміщується після першого зображення, є останній зображення, яке має вищий порядок у DOM. Решта зображень добре, тому що ми маємо N, То N - 1, то йдемо з 3 до 2 та 2 до 1… але потім ми йдемо з 1 до N.

Щоб уникнути цього, ми використаємо такі ключові кадри для останнього зображення:

@keyframes slide-last {
  0%     { transform: translateX(0%);   z-index: 2;}
  16.66% { transform: translateX(120%); z-index: 2; }
  16.67% { transform: translateX(120%); z-index: 1; } /* we update the z-order here */
  33.34% { transform: translateX(0%);   z-index: 1; }
  83.33% { transform: translateX(0%);   z-index: 1; }
  83.34% { transform: translateX(0%);   z-index: 2; } /* and also here */
  100%   { transform: translateX(0%);   z-index: 2; }
}

Ми скидаємо z-index значення 5/6 через анімацію (замість двох третин), коли перше зображення виходить із стопки. Тож стрибків не бачимо!

ТАДА! Наш нескінченний слайдер тепер ідеальний! Ось наш остаточний код у всій його красі:

.gallery > img {
  animation: slide 6s infinite;
}
.gallery > img:last-child {
  animation-name: slide-last;
}
.gallery > img:nth-child(2) { animation-delay: -2s; } 
.gallery > img:nth-child(3) { animation-delay: -4s; }

@keyframes slide {
  0% { transform: translateX(0%); z-index: 2; }
  16.66% { transform: translateX(120%); z-index: 2; }
  16.67% { transform: translateX(120%); z-index: 1; } 
  33.34% { transform: translateX(0%); z-index: 1; }
  66.33% { transform: translateX(0%); z-index: 1; }
  66.34% { transform: translateX(0%); z-index: 2; } 
  100% { transform: translateX(0%); z-index: 2; }
}
@keyframes slide-last {
  0% { transform: translateX(0%); z-index: 2; }
  16.66% { transform: translateX(120%); z-index: 2; }
  16.67% { transform: translateX(120%); z-index: 1; }
  33.34% { transform: translateX(0%); z-index: 1; }
  83.33% { transform: translateX(0%); z-index: 1; }
  83.34% { transform: translateX(0%); z-index: 2; } 
  100%  { transform: translateX(0%); z-index: 2; }
}

Підтримка будь-якої кількості зображень

Тепер, коли наша анімація працює для трьох зображень, давайте змусимо її працювати для будь-якої кількості (N) зображень. Але спочатку ми можемо трохи оптимізувати нашу роботу, розділивши анімацію, щоб уникнути надмірності:

.gallery > img {
  z-index: 2;
  animation: 
    slide 6s infinite,
    z-order 6s infinite steps(1);
}
.gallery > img:last-child {
  animation-name: slide, z-order-last;
}
.gallery > img:nth-child(2) { animation-delay: -2s; } 
.gallery > img:nth-child(3) { animation-delay: -4s; }

@keyframes slide {
  16.67% { transform: translateX(120%); }
  33.33% { transform: translateX(0%); }
}
@keyframes z-order {
  16.67%,
  33.33% { z-index: 1; }
  66.33% { z-index: 2; }
}
@keyframes z-order-last {
  16.67%,
  33.33% { z-index: 1; }
  83.33% { z-index: 2; }
}

Зараз значно менше коду! Ми робимо одну анімацію для ковзної частини та іншу для z-index оновлення. Зверніть увагу, що ми використовуємо steps(1) на z-index анімація. Це тому, що я хочу різко змінити z-index значення, на відміну від ковзної анімації, де ми хочемо плавний рух.

Тепер, коли код легше читати та підтримувати, ми маємо кращий погляд, щоб зрозуміти, як підтримувати будь-яку кількість зображень. Нам потрібно оновити затримки анімації та відсоток ключових кадрів. Затримка проста, тому що ми можемо використовувати той самий цикл, який ми зробили в попередній статті, щоб підтримувати кілька зображень у круглому повзунку:

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

Це означає, що ми переходимо від ванільного CSS до Sass. Далі нам потрібно уявити, як масштабується шкала часу N зображення. Не забуваймо, що анімація відбувається в три фази:

Показ трьох частин анімації в рядах ліній зі стрілками.
CSS Infinite Slider гортає зображення Polaroid

Після «ковзання праворуч» і «ковзання ліворуч» зображення має залишатися на місці, доки решта зображень не пройдуть через послідовність. Отже, частина «не рухайся» потребує стільки ж часу, скільки (N - 1) як «ковзання праворуч» і «ковзання ліворуч». І протягом однієї ітерації, N зображення будуть ковзати. Отже, «ковзання праворуч» і «ковзання ліворуч» обидва беруть 100%/N із загальної шкали часу анімації. Зображення ковзає з купи на (100%/N)/2 і ковзає назад на 100%/N .

Ми можемо це змінити:

@keyframes slide {
  16.67% { transform: translateX(120%); }
  33.33% { transform: translateX(0%); }
}

…до цього:

@keyframes slide {
  #{50/$n}%  { transform: translateX(120%); }
  #{100/$n}% { transform: translateX(0%); }
}

Якщо замінимо N з 3, ми отримуємо 16.67% та 33.33% коли є 3 зображень у стеку. Така сама логіка з порядком стекування, де ми матимемо це:

@keyframes z-order {
  #{50/$n}%,
  #{100/$n}% { z-index: 1; }
  66.33% { z-index: 2; }
}

Нам ще потрібно оновити 66.33% точка. Передбачається, що це місце, де зображення скидається z-index до кінця анімації. У той же час наступне зображення починає ковзати. Так як висувна частина займає 100%/N, скидання має відбутися о 100% - 100%/N:

@keyframes z-order {
  #{50/$n}%,
  #{100/$n}% { z-index: 1; }
  #{100 - 100/$n}% { z-index: 2; }
}

Але для наших z-order-last щоб анімація працювала, це має статися трохи пізніше в послідовності. Пам’ятаєте, що ми зробили для останнього зображення? Скидання z-index значення має статися, коли перше зображення виходить із стопки, а не коли воно починає ковзати. Ми можемо використати те саме міркування тут у наших ключових кадрах:

@keyframes z-order-last {
  #{50/$n}%,
  #{100/$n}% { z-index: 1; }
  #{100 - 50/$n}% { z-index: 2; }
}

Ми готові! Ось що ми отримуємо, використовуючи п’ять зображень:

Ми можемо додати трохи обертання, щоб зробити речі трохи привабливішими:

Все, що я зробив, це додав rotate(var(--r)) до transform власність. Всередині петлі, --r визначається випадковим кутом:

@for $i from 1 to ($n + 1) {
  .gallery > img:nth-child(#{$i}) {
    --r: #{(-20 + random(40))*1deg}; /* a random angle between -20deg and 20deg */
  }
}

Обертання створює невеликі збої, оскільки іноді ми бачимо, як деякі зображення перескакують на кінець стека, але це не має великого значення.

Підводячи підсумок

Все, що z-index робота була великим балансуванням, чи не так? Якщо до цієї вправи ви не були впевнені, як працює порядок укладання, то зараз у вас, мабуть, є набагато краще уявлення! Якщо вам було важко дотримуватись деяких пояснень, я настійно рекомендую вам ще раз прочитати статтю та малювати речі олівцем і папером. Спробуйте проілюструвати кожен крок анімації, використовуючи різну кількість зображень, щоб краще зрозуміти трюк.

Минулого разу ми використали кілька геометричних хитрощів, щоб створити круглий повзунок, який повертається до першого зображення після повної послідовності. Цього разу ми зробили подібний трюк, використовуючи z-index. В обох випадках ми не дублювали жодне зображення, щоб імітувати безперервну анімацію, і не використовували JavaScript, щоб допомогти з обчисленнями.

Наступного разу ми будемо робити 3D слайдери. Залишайтеся на зв'язку!

Часова мітка:

Більше від CSS-хитрощі