Анимация бесконечной прокрутки на чистом CSS
В этой демонстрации создадим компонент, который с помощью CSS-анимаций будет имитировать бесконечно прокручивающуюся ленту карточек. Вы, наверняка, видели подобные компоненты на сайтах, например, в промоблоке или в галерее.
Исходное состояние — список с карточками категорий продуктов.
Поработаем с контейнером для карточек. В нашем случае — это список .carousel
. Сбросим стили для списка по умолчанию. Ограничим по ширине. Укажем нужные поля. За счёт автоматического внешнего отступа слева и справа разместим список по центру.
Чтобы выстроить карточки в ряд, используем display: grid
. С помощью настройки грида будем определять внешний вид компонента. Количество колонок — это количество видимых карточек, ширина колонки — это ширина карточки.
Всё что не поместилось в контейнер, скроем с помощью overflow: hidden;
.
Чтобы отлепить карточки друг от друга, зададим прозрачную границу по бокам карточек. Используем новое CSS-свойство border-inline
.
gap
в нашем случае не подойдёт, поэтому приходится выкручиваться другими способами.
Для карточек укажем координаты внутри грид-контейнера. Для всех карточек будет одно и тоже значение — первая колонка, первая строка. Это стартовая позиция карточки для будущей анимации.
Чтобы было нагляднее и проще разобраться как работает анимация, оставим в разметке только одну карточку.
Также для наглядности уберём overflow: hidden;
. Добавим вместо него рамку, чтобы выделить границы контейнера. Немного уменьшим размер карточек.
Добавим для карточки анимацию scrolling
. Установим время для проигрывания анимации 15 секунд
. Будем повторять анимацию бесконечно.
Подробно разберём, что происходит во время анимации.
Мы перемещаем карточки из положения translate(-100%)
в положение translate(500%)
. Значения выбраны не случайно. Всего карточек шесть. Путь, который пройдёт карточка, должен быть равен суммарной ширине всех карточек (6 * 100% = 600%
). Поскольку нужно, чтобы карточка уходила за рамки контейнера, левую границу для смещения с нуля процентов мы подвинем на ширину карточки или 100%
. А это значит, что и правая граница смещения также подвинется влево на это значение и будет равна 500%
.
Также не случайно выбраны ключевые кадры для анимации. Первый ключевой кадр 16.67%
— это 100% / количество карточек
. Второй — максимально близкое к первому ключевому кадру значение 16.67% + 0.01%
. Нужно, чтобы из точки translate(-100%)
карточка как можно быстрее переместилась в точку translate(500%)
.
Перед тем как добавить анимацию для других карточек, снова поменяем разметку. Временно добавим ещё один контейнер, в котором также будет перемещаться одна карточка.
Вторую карточку будем запускать с небольшой задержкой (animation-delay
). Значение для animation-delay
установим из расчёта, что нам нужно запускать карточки через равные промежутки времени. Также задержка для последней карточки должна быть такой, чтобы все карточки успели пройти одну итерацию анимации до того, как первая карточка пойдёт на очередной круг.
После сложных умозаключений, получается следующая формула:
(1 - порядковый_номер_элемента) / всего_элементов * время_анимации
Для вычислений используем функцию calc()
.
Для третьей карточки также добавим свой контейнер. Опять же для наглядности.
Для третьей карточки также добавим задержку, которую вычислим по нашей формуле:
(1 - порядковый_номер_элемента) / всего_элементов * время_анимации
Порядковый номер элемента — 3
.
Пересчитаем для третьего элемента время задержки, как будто это элемент под номером 4
.
Пересчитаем для третьего элемента время задержки, как будто это элемент под номером 5
.
Для последнего шестого элемента попробуйте самостоятельно подставить значение CSS-свойства animation-delay
.
Соберём все карточки в один контейнер. И поменяем селекторы для правил, чтобы они применились для элементов внутри списка.
Уберём обводку и вернём overflow: hidden;
.
Для карточек установим начальную ширину.
Чтобы было удобнее нажать на ссылку в карточке и перейти в соответствующую категорию товаров, будем останавливать карусель при наведении.
Попробуйте навести указатель мыши на любую из карточек.
Подскажем браузеру, что во время анимации будем изменять CSS-свойство transform
.
Вынесем в CSS-переменные время анимации и количество элементов. Так будет проще выполнять настройку компонента, поменяв значения на нужные.
Также за счёт CSS-переменных сократим количество правил. Для начала добавим в разметку каждого элемента списка атрибут style
с переменной --i
.
И вместо пяти правил добавим одно свойство в правило для .carousel__item
:
animation-delay: calc((1 - var(--i)) / var(--count-items) * var(--animation-time));
Бесконечная карусель готова!