Статьи

Анимация загрузочных каруселей с библиотекой анимации GSAP

В предыдущем посте я рассмотрел процесс преобразования карусели Bootstrap в полноэкранную карусель со случайным исходным изображением. В этой статье я расскажу об этом и расскажу об искусстве анимации каруселей Bootstrap, опираясь на помощь GSAP (GreenSock Animation Platform), популярной библиотеки JavaScript.

Анимационные карусели Bootstrap: карусельная лошадь в накидке GSAP

Прежде чем идти дальше, давайте посмотрим, что мы будем строить .

Построение Карусели

Обязательно включите Bootstrap и jQuery (это требуется для компонентов JavaScript Bootstrap) на вашей странице — например, из CDN:

<!DOCTYPE HTML> <html> <head> <meta charset="utf-8"> <title>Using GSAP for Animating Bootstrap Carousels</title> <link rel="stylesheet" type="text/css" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css"> </head> <body> ... <script src="https://code.jquery.com/jquery-3.2.1.slim.min.js"></script> <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js"></script> </body> </html> 

Базовая структура нашей карусели выглядит так:

 <div id="mycarousel" class="carousel slide" data-ride="carousel"> <ol class="carousel-indicators"> <li data-target="#mycarousel" data-slide-to="0" class="active"></li> <li data-target="#mycarousel" data-slide-to="1"></li> </ol> <div class="carousel-inner"> <!-- first slide --> <div class="carousel-item first active" id="1"> <!-- content here --> </div> <!-- second slide --> <div class="carousel-item second" id="2"> <!-- content here --> </div> </div><!-- /carousel-inner --> </div> 

Как видите, он содержит два слайда. Первый слайд имеет класс first и идентификатор 1 , а второй — класс second и ID 2 .

Что касается их стилей:

  • мы устанавливаем их высоту, равную высоте области просмотра
  • мы даем им разные цвета фона.

Соответствующие правила CSS:

 .item { height: 100vh; } .first { background: #D98F4F; /*orange*/ } .second { background: #2c9cae; /*lightblue*/ } 

Этого должно быть достаточно, чтобы дать нам работающую карусель.

Создание первого слайда

Далее мы используем преимущества вспомогательных классов Bootstrap (например, классов сетки ) для настройки содержимого наших слайдов.

Разметка для первого слайда следующая:

 <div class="carousel-item first active" id="1"> <div class="carousel-caption"> <div class="container"> <div class="row justify-content-md-center"> <div class="col"> <h2 class="title"> <!-- content here --> </h2> <p class="desc"> <!-- content here --> </p> <ul class="list"> <!-- list items here --> </ul> </div> <div class="col"> <div class="pc-wrapper"> <img class="pc" src="IMG_PATH" alt="" width="" height=""> <div class="price"> <!-- content here --> </div><!-- /price --> </div><!-- /pc-wrapper --> <img class="keyboard" src="IMG_PATH" alt="" width="" height=""> <button type="button" class="btn btn-danger btn-lg"> <!-- content here --> </button> </div> </div><!-- /row --> </div><!-- /container --> </div><!-- /carousel-caption --> </div><!-- /carousel-item --> 

Если вы следуете вперед, обязательно замените IMG_PATH на что-нибудь разумное.

Вот как выглядит результат:

Анимационная Bootstrap Carousels: первый слайд карусели

Создание второго слайда

Таким же образом, вот разметка для второго слайда:

 <div class="carousel-item second" id="2"> <div class="carousel-caption"> <div class="container"> <h2 class="title"> <span> <!-- content here --> </span> </h2> <div class="row justify-content-md-center"> <div class="col cms-wrapper"> <div class="cms"> <div class="front"> <!-- content here --> </div> <div class="back"> <img class="img-fluid" src="IMG_PATH" alt=""> </div><!-- /back --> </div><!-- /cms --> <p class="info"> <!-- content here --> </p> </div><!-- /cms-wrapper --> <!-- two more columns here --> </div><!-- /row --> <div class="source"> <!-- content here --> </div><!-- /source --> </div><!-- /container --> </div><!-- /carousel-caption --> </div><!-- /carousel-item --> 

И его визуализация:

Анимационная Bootstrap Carousels: вторая слайд карусели

Примечание. Для простоты мы не будем подробно рассматривать стили внутренних частей слайдов. Мы будем ссылаться только на стили, которые важны для анимации.

Инициализация карусели

Затем мы инициализируем карусель и отключаем автозапуск по умолчанию, передавая interval:false для объекта конфигурации:

 var $carousel = $("#mycarousel"); $carousel.carousel({ interval: false }); 

Добавление клавиатуры навигации

По умолчанию карусель Bootstrap не соответствует стандартам доступности. В нашем случае, тем не менее, давайте сделаем карусель немного более доступной, добавив навигацию с помощью клавиатуры.

Вот необходимый код:

 $(document).keyup(function(e) { // right arrow if(e.which === 39) { $carousel.carousel("next"); // left arrow } else if(e.which === 37) { $carousel.carousel("prev"); } }); 

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

Анимация Bootstrap Карусели: первые анимации

На этом этапе давайте попробуем сделать карусель более привлекательной, добавив анимацию. Чтобы достичь этого, мы воспользуемся GSAP, одной из самых мощных библиотек анимации JavaScript. Если вы ищете подробное введение в GreenSock, ознакомьтесь с GreenSock для начинающих: учебник по веб-анимации (часть 1) .

Начало работы с GSAP

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

Как скачать GSAP

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

Как включить GSAP в нашу демонстрацию Codepen

Помните, что нам пришлось добавить jQuery в наш проект, потому что от этого зависит карусель Bootstrap. Но имейте в виду, что GSAP — это чистая библиотека JavaScript, и поэтому она не требует этого.

Анимация Bootstrap Карусели: первый слайд

По умолчанию мы хотим, чтобы содержимое наших слайдов было скрыто:

 .carousel-caption { opacity: 0; } 

Только когда страница загружается, мы открываем и анимируем содержимое первого слайда. Для этого мы используем TimelineLite , инструмент для анимации, который помогает нам создавать последовательность анимации.

Итак, как только все ресурсы страницы готовы, firstTimeline функция firstTimeline :

 // this variable stores the first timeline var firstTl; $(window).on("load", function() { firstTl = firstTimeline(); }); 

Эта функция возвращает временную шкалу, которая определяет анимацию для первого слайда:

 function firstTimeline() { var tl = new TimelineLite(); tl .to(".first .carousel-caption", 0.1, {opacity: 1}) .from(".first .pc", 1, { y: -300, opacity: 0, ease: Bounce.easeOut}) .from(".first .keyboard", 1, { y: 300, opacity: 0, ease: Bounce.easeOut}, "-=1") .staggerFrom(".first .list li", 0.75, {opacity: 0, cycle: {x: [-200, 200]}, ease: Power2.easeOut}, 0.15, "-=0.5") .from(".first .desc", 0.7, {x: 500, opacity: 0, ease: Power4.easeOut}, "-=0.5") .from(".first .title", 0.7, {x: -500, opacity: 0, ease: Power2.easeOut}, "-=0.7") .from(".first .price", 0.7, {scale: 0.01, ease: Power4.easeOut}) .from(".first button", 0.7, { y: -700, autoAlpha: 0, ease: Bounce.easeOut}, "-=0.3"); return tl; } 

Более конкретно, внутри функции выше мы делаем следующее:

  1. создать TimelineLite
  2. добавьте анимацию на временную шкалу, используя методы to , from и staggerFrom
  3. вернуть график.

Давайте обратим внимание на параметры, которые мы передаем методам to и from :

  1. Элемент DOM, который мы хотим анимировать.
  2. Продолжительность анимации в секундах.
  3. Объект, содержащий свойства, которые необходимо анимировать, и их соответствующие (начальное или конечное) значения. Кроме того, этот объект может также иметь некоторые другие специальные свойства, такие как свойство ease которое определяет функцию замедления .
  4. Размещение анимации на временной шкале. Другими словами, когда эта анимация должна быть исполнена . Например, мы хотим запустить анимацию для .first .pc и .first .keyboard одновременно. Для этого мы устанавливаем значение параметра .first .keyboard элемента .first .keyboard "-=1" . Число «1» внутри этого значения соответствует продолжительности анимации элемента .first .pc .

Подобно методам to и from , мы передаем те же параметры методу staggerFrom . Единственное отличие состоит в том, что мы определяем один дополнительный параметр (четвертый), который определяет время начала каждой анимации. В нашем примере это значение установлено на 0.15 . Тем не менее, целевые элементы не будут появляться одновременно, но между их анимациями будет очень небольшой разрыв. Измените это значение на что-то большое (например, 5), чтобы увидеть явную разницу в эффекте.

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

Итак, давайте кратко рассмотрим анимацию, назначенную кнопке.

Изначально у кнопки есть autoAlpha: 0 Это означает, что он визуально скрыт ( opacity: 0 , visibility: hidden ) и расположен на 700 пикселей выше его исходного положения ( transform: matrix(1, 0, 0, 1, 0, -700) ).

Карусели анимации начальной загрузки: какие стили изначально GSAP применяет к кнопке перед анимацией

Затем, когда анимация воспроизводится, она становится видимой ( opacity: 1 , visibility: inherit ) и возвращается в исходное положение ( transform: matrix(1, 0, 0, 1, 0, 0) ).

Карусели анимации начальной загрузки: какие стили в конце концов GSAP применяет к кнопке после анимации

Наконец, анимация начинается за 0,3 секунды до окончания временной шкалы.

Совет: Используйте метод duration TimelineLite, чтобы получить его продолжительность. Ключевым моментом здесь является понимание того, как рассчитывается это значение.

Отличная работа! Анимации для первого слайда готовы! Вы можете увидеть их вживую в этой демонстрации Codepen: Использование GSAP для анимации загрузочных каруселей (часть 1) .

Использование событий Карусели Bootstrap

Когда мы покидаем первый слайд и переходим ко второму (и наоборот), содержимое наших слайдов должно быть скрыто. Он должен появиться, как только карусель завершит слайд-переход. Чтобы выполнить это поведение, мы используем следующие преимущества:

  1. События slide.bs.carousel и slid.bs.carousel которые предоставляет Bootstrap.
  2. GSAP — инструмент анимации TweenLite , который помогает нам создать единую анимацию. Обратите внимание, что в предыдущем разделе мы использовали TimelineLite для создания последовательности анимации.

Вот необходимый код:

 var $carouselCaption = $(".carousel-caption"); $carousel.on("slide.bs.carousel", function() { TweenLite.to($carouselCaption, 0.1, {opacity: 0}); }); $carousel.on("slid.bs.carousel", function () { TweenLite.to($carouselCaption, 0.1, {opacity: 1}); }); 

Как мы уже говорили ранее, при загрузке страницы запускаются анимации для первого слайда. Но когда они должны снова бежать? Плюс, как насчет второго слайда и его анимации? Чтобы ответить на все эти вопросы, давайте добавим несколько строк кода к slid.bs.carousel события slid.bs.carousel :

 // these variables store the timelines var firstTl, secondTl; $carousel.on("slid.bs.carousel", function (e) { TweenLite.to($carouselCaption, 0.1, {opacity: 1}); var slideId = e.relatedTarget.id; if(slideId === "1") { firstTl.restart(); } else if(slideId === "2") { secondTl = secondTimeline(); } }); 

Код выше делает следующее:

  1. Он проверяет id наших слайдов.
  2. Если id равен 1 , первый слайд был загружен, и поэтому мы должны воспроизвести анимацию для этого слайда. Помните, что мы уже создали временную шкалу для этих анимаций (в рамках функции firstTimeline ), поэтому мы можем использовать метод restart чтобы воспроизвести ее снова.
  3. Если id равен 2 , второй слайд был загружен, и, таким образом, secondTimeline функция secondTimeline (см. Следующий раздел).

Анимация Bootstrap Карусели: второй слайд

Функция secondTimeline возвращает временную шкалу, которая определяет анимацию для второго слайда:

 function secondTimeline() { var tl = new TimelineLite({onComplete: allDone}); tl .from(".second .title", 0.5, { y: -400, opacity: 0, ease: Sine.easeInOut}) .staggerFrom(".second .cms-wrapper", 0.5, {scale: 0, rotation: 180, ease: Power2.easeInOut, onComplete: completeFunc}, 1.2); return tl; } 

Более конкретно, внутри функции выше мы делаем следующее:

  1. создать TimelineLite
  2. добавьте анимацию к временной шкале, используя методы from и staggerFrom
  3. вернуть график.

Хотя эта временная шкала выглядит как та, которую мы ранее создали для первого слайда, здесь есть некоторые вещи, которые мы раньше не видели.

Сначала посмотрите на объект, который мы staggerFrom методу staggerFrom . Он содержит специальное свойство onComplete . Это свойство содержит функцию (то есть completeFunc() ), которая запускается, когда completeFunc() анимация для каждого целевого элемента.

Позволь мне объяснить.

По умолчанию видны только элементы с классом .second .front (то есть числами).

Как элемент cms-wrapper второго слайда изначально выглядит до анимации

И .second .back (т.е. логотипы CMS) и .second .info (т.е. имена CMS) скрыты.

Вот соответствующие правила CSS:

 .second .back { display: none; transform: scale(0); } .second .info { opacity: 0; transform: translateY(40px); } 

Когда функция completeFunc запускается для каждого из .second .cms-wrapper , мы настраиваем анимацию, которая влияет на видимость дочерних элементов. В частности, мы .second .front элемент .second .front и затем показываем (после задержки 0,3 секунды) .second .back и .second .info .

Как выглядит элемент cms-wrapper второго слайда после анимации

Ниже вы можете увидеть соответствующий код JS:

 function completeFunc() { var $this = $(this.target), $info = $this.find(".info"), $front = $this.find(".front"), $back = $this.find(".back"); TweenLite.to($front, 0.3, {display: "none", scale: 0}); TweenLite.to($back, 0.3, {display: "block", scale: 1, delay: 0.3}); TweenLite.to($info, 0.3, {opacity: 1, y: 0, delay: 0.3}); } 

Вторая новая вещь на этой временной шкале — обратный вызов, который запускается, когда заканчиваются все анимации. Мы определяем это, передавая объект конфигурации со свойством onComplete (значением которого является функция allDone ) в функцию конструктора.

Когда временная шкала завершается, эта функция запускается и показывает элемент .second .source который изначально был невидим ( opacity: 0 , visibility: hidden ).

Анимация Bootstrap Carousels: как выглядит исходный элемент второго слайда после анимации

Вот функция allDone :

 function allDone() { TweenLite.to(".second .source", 0.3, {autoAlpha: 1, delay: 1}); } 

На этом этапе давайте рассмотрим текущее состояние нашей карусели: Использование GSAP для анимации загрузочных каруселей (часть 2) .

Анимации выглядят хорошо, но все же есть небольшая проблема со вторым слайдом. Чтобы быть более конкретным, при первом посещении второго слайда анимация работает, как и ожидалось. Однако в любом другом случае (протестируйте его) результат не является желаемым, поскольку логотипы CMS не анимируются.

Чтобы решить эту проблему, мы должны перезапустить соответствующую временную шкалу (помните, что мы сделали то же самое для первого слайда) и очистить анимации (встроенные стили), определенные в функциях completeFunc и allDone . Наконец, мы приостанавливаем вторую временную шкалу, когда первая активна. Имея это в виду, мы снова обновляем обратный slid.bs.carousel события slid.bs.carousel следующим образом:

 var counter = 0, firstTl, secondTl; $carousel.on("slid.bs.carousel", function (e) { TweenLite.to($carouselCaption, 0.1, {opacity: 1}); var slideId = e.relatedTarget.id; if(slideId === "1") { firstTl.restart(); secondTl.pause(); } else if(slideId === "2") { if(counter === 0) { secondTl = secondTimeline(); } else { TweenLite.set([".second .front", ".second .back", ".second .info", ".second .source"], {clearProps:"all"}); secondTl.restart(); } counter++; } }); 

Итак, наконец, вот новая версия нашей карусели: Использование GSAP для анимации загрузочных каруселей (часть 3) .

Настройка карусели при отключенном JavaScript

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

Вот желаемая визуализация:

Как выглядит карусель с отключенным JavaScript

Один из способов реализовать это поведение — использовать <noscript> . Эта опция хороша, но она добавляет некоторый дополнительный код в наш HTML, поэтому давайте попробуем немного по-другому.

По умолчанию мы добавляем класс no-js в <html> . Когда браузер анализирует страницу, если в этом браузере включен JavaScript, класс удаляется.

Итак, во-первых, в HTML мы добавим этот код:

 <p class="msg"> It seems you have JavaScript disabled. The carousel doesn't work well without JavaScript. Please enable it! </p> 

Затем в CSS это (в основном правила сброса):

 .msg { display: none; position: fixed; top: 5px; left: 50%; transform: translateX(-50%); padding: 7px; border: 5px solid #fff000; text-align: center; color: #fff; background: rgba(0, 0, 0, .85); z-index: 999; } .no-js .carousel-inner > .item { display: block; } .no-js .carousel-caption, .no-js .second .info, .no-js .second .source { opacity: 1; } .no-js .second .info { transform: none; } .no-js .second .source { visibility: visible; } .no-js .carousel-indicators { display: none; } .no-js .msg { display: block; } 

Наконец, в <head> нашей страницы мы вставляем следующий фрагмент кода:

 <script> document.documentElement.className = ""; </script> 

Удаление класса no-js из элемента HTML

Помните, что мы помещаем этот код в <head> потому что мы хотим, чтобы он выполнялся до того, как браузер начнет рисовать элементы. Это важно для предотвращения мерцания DOM.

Вот финальная версия нашей карусели:

Вывод

В этой статье мы рассмотрели процесс анимации каруселей Bootstrap с помощью GSAP. Вы можете найти все демонстрационные материалы для этой статьи в этой коллекции Codepen . Без сомнения, мы многое изучили, но, надеюсь, вам понравилось то, что мы создали, и вы получили представление о силе GSAP! Счастливой твининг!

Вопросов? Комментарии? Используете ли вы GSAP в своих проектах? Я хотел бы услышать от вас в комментариях ниже.

Эта статья была рецензирована Джоан Инн и Яфи Берхану . Спасибо всем рецензентам SitePoint за то, что сделали контент SitePoint как можно лучше!

Если у вас есть основы Bootstrap за поясом, но вы не знаете, как поднять свои навыки Bootstrap на следующий уровень, ознакомьтесь с нашим курсом «Создайте свой первый сайт с Bootstrap 4», чтобы быстро и весело познакомиться с мощью Bootstrap.