Статьи

Реализация страниц с помощью API веб-анимации

Эта статья написана гостем Гостевые посты SitePoint нацелены на привлечение интересного контента от известных авторов и спикеров сообщества JavaScript.

Один API, чтобы управлять ими всеми

Анимация в Интернете уже давно разделена на четыре разнородных лагеря:

  • CSS-переходы и анимации очень производительны и обеспечивают создание ключевых кадров, но также требуют много времени для сборки и обеспечивают только базовое начальное и конечное управление в CSS и JavaScript . Это, как правило, сводит их к простой анимации ответа пользовательского интерфейса, циклам и анимации загрузки страницы.
  • SMIL (Synchronized Multimedia Integration Language) очень мощный, но он также синтаксический и имеет неполную поддержку браузера. Он также ограничен управлением элементами исключительно в контексте SVG.
  • JavaScript предлагает прямое управление элементами, но не понимает удобных для дизайнера функций, таких как ключевые кадры или замедление, и не имеет встроенной оптимизации и производительности CSS. Анимация Canvas API замечательна, но все еще не имеет понимания основ анимации и не может анимировать произвольные элементы DOM.
  • Фреймворки JavaScript-анимации, такие как Greensock, пытаются преодолеть традиционные недостатки JavaScript, когда дело доходит до анимации, но имеют все связанные с этим недостатки фреймворков: загрузку страницы, производительность и изучение нового синтаксиса.

API веб-анимаций стремится объединить лучшие функции всех этих компонентов в единую унифицированную спецификацию , устраняя при этом недостатки, создавая естественное понимание ключевых кадров, упрощение и управление элементами в JavaScript, с той же производительностью на экране, что и CSS , Теперь, когда основные компоненты спецификации поддерживаются в Chrome и Firefox , а разработка либо анонсирована, либо ведется разработка в других браузерах, включая Safari и Edge , а также наличие надежного полифилла , пришло время серьезно подумать об API веб-анимации для создания веб-сайтов. страницы к жизни.

Ключевые кадры в JavaScript

Давайте рассмотрим один из самых простых примеров анимации ключевого кадра: перемещение элемента красного шара с одной стороны страницы на другую. Независимо от того, какую технику мы используем, элемент будет одинаковым:

<div id="redball"></div> 

Как будет исходный CSS:

 body { margin: 0; background: #000; overflow: hidden; min-height: 100vh; } #redball { background: red; width: 30vmin; height: 30vmin; border-radius: 50%; } 

Я использовал vmin измерения vmin чтобы элемент всегда оставался симметричным, отвечая размеру области просмотра.

В CSS перемещение шарика с одной стороны страницы на другую потребует что-то вроде следующего:

 @keyframes moveBall { from { transform: translateX(-20vw); } to { transform: translateX(100vw); } } 

Эта анимация будет вызываться из объявления для элемента красного шара:

 #redball { animation: moveBall 3s infinite; } 

Результат, показанный в Codepen:

На данный момент есть несколько моментов, которые стоит отметить в отношении анимации, в том числе тот факт, что замедление (ускорение в начале и замедление в конце) автоматически встроено.

Введите API веб-анимации

Сохраняя HTML и начальные стили, давайте удалим CSS-анимацию и заменим JavaScript, который использует API веб-анимации для достижения той же цели:

 var moveBall = document.getElementById('redball').animate([{ transform: 'translateX(-20vw)' }, { transform: 'translateX(100vw)' }], { duration: 3000, iterations: Infinity, easing: 'ease' }); 

Вы можете видеть, что анимация принимает почти тот же синтаксис, что и CSS, но представляет ее как объект с массивом, представляющим ключевые кадры. Нам не нужно явно декларировать ключевые кадры или from — JavaScript автоматически распределит ключевые кадры для нас равномерно, хотя объявление также вполне возможно.

Анимация пока не будет проигрываться; как и в CSS, мы должны назвать это:

 moveBall.play(); 

Часть синтаксиса ключевого кадра станет еще проще в будущих браузерах, поскольку аспекты синтаксиса преобразования CSS, которые были ранее значениями, станут доступны в виде свойств :

 translateX: -20vw; 

Это изменение спецификации уже доступно в Chrome Canary, но пройдет год или два, прежде чем новый синтаксис станет доступен во всех современных браузерах.

Есть еще несколько моментов, которые стоит отметить в скрипте:

  • JavaScript берет время анимации в миллисекундах, а не в стандартных секундах CSS (миллисекунды также доступны в CSS, если к значению синхронизации добавляется ms ).
  • API веб-анимации определяет число итераций в качестве iterations , а не свойство CSS interation-count (если он определен отдельно); Ключевое слово — Infinity (с заглавной буквой I) для количества повторений, а не CSS для infinite
  • В API веб-анимации ослабление по умолчанию является linear , поэтому в нашей демонстрации мы указываем значение по умолчанию для CSS-анимации.

Результат функционально эквивалентен анимации CSS.

Конечно, дублирование CSS-анимации, подобной этой, в JavaScript на самом деле не использует динамизм языка сценариев почти до максимальной производительности; чтобы продемонстрировать это, мы создадим гораздо более полнофункциональную анимацию.

Дилинг изображения

Стек изображений, анимированных с помощью API веб-анимации.

Некоторое время назад я был заинтересован в создании анимации, которая наносила серию изображений на веб-страницу, например, подбрасывая игральные карты на стол. Написание отдельных анимаций для каждой карты в традиционном CSS заняло бы много времени и всегда давало бы один и тот же результат. Вместо этого я использовал API веб-анимации как идеальный инструмент для работы.

Прогрессивные карты

Мы хотим, чтобы изображения отображались независимо от того, включен JavaScript или API веб-анимации или нет, поэтому начнем с добавления серии изображений на страницу:

 <div class="shuffle expose"> <img src="bridgefog.jpg" alt> <img src="daisyface.jpg" alt> <img src="drowninghand.jpg" alt> <img src="firefigure.jpg" alt> <img src="shellhand.jpg" alt> <img src="waterfeet.jpg" alt> </div> 

Я оставил значения alt изображений пустыми, чтобы код был чистым; в рабочей версии они будут заполнены описаниями. Фотографии предоставлены .tafo. , используется в соответствии с лицензией Creative Commons Attribution-NoDerivs 2.0 .

Мы можем добавить немного CSS для добавления изображений с анимацией, если условие без JavaScript все еще выполняется:

 @keyframes reveal { to { opacity: 1; } } .shuffle { min-height: 100vh; position: relative; } .shuffle img { width: 33%; opacity: 0; } .expose img { animation: reveal 1s forwards; } 

Доставка отдельного изображения может быть отложена с помощью:

 .expose img:nth-child(1) { animation-delay: 1s; } .expose img:nth-child(2) { animation-delay: 2s; } .expose img:nth-child(3) { animation-delay: 3s; } 

Естественно, эти объявления могут быть автоматизированы с помощью Sass или другого препроцессора.

Изображения будут иметь границу, если родительский элемент имеет class webanim , который будет применяться с JavaScript:

 div.webanim img { border: 1.4vw solid #eee; } 

JavaScript

Мы добавим скрипт в конец страницы. Мне понадобится несколько случайных значений в анимации, поэтому я создам функцию для их создания:

 function getRandom(min, max) { return Math.random() * (max - min) + min; } 

Затем я соберу контейнер изображений и все изображения внутри них, вместе с установкой переменной incrementor:

 var imgContainer = document.querySelector(".expose"), imgSeq = document.querySelectorAll(".shuffle img"), i = 1; 

Затем я удалю класс expose (оставив изображения с непрозрачностью 0 и не анимированные), поскольку CSS-анимация работает, только если контейнер имеет класс expose:

 imgContainer.classList.remove("expose"); imgContainer.classList.add("webanim"); 

Класс webanim размещает изображения с рамкой.

Основная часть скрипта выполняется в цикле forEach внутри функции. Я вызову функцию, как только буду уверен, что все данные изображения загружены (в отличие от узлов изображения, просто появляющихся в DOM), используя отличный сценарий imagesLoaded от David DeSandro :

 function racknstack() { Array.prototype.forEach.call(imgSeq, function(photo) { setTimeout(function() { photo.style.position = "absolute"; photo.style.width = getRandom(33, 45) + "%"; photo.style.left = getRandom(-5, 65) + "%"; photo.style.top = getRandom(-6, 60) + "vh"; var animate = photo.animate([{ opacity: '0', transform: 'rotate(' + getRandom(-12, 12) + 'deg) scale(1.2)', boxShadow: '0 0 12px 12px rgba(0,0,0,.3)' }, { opacity: '1', transform: 'rotate(' + getRandom(-8, 8) + 'deg)', boxShadow: '0 0 6px 6px rgba(0,0,0,.3)' }], { duration: 2000, fill: 'forwards' }); }, 1800 * i) i++; }) } 

Как и прежде, мы должны вызвать функцию, чтобы начать все с:

 imagesLoaded(imgSeq, racknstack); 

Результат:

В свою очередь, функция:

  • устанавливает каждое изображение в абсолютную позицию;
  • генерирует случайную ширину для изображения (в процентах, поэтому изображение остается плавным и отзывчивым)
  • генерирует случайное положение для изображения (включая возможное отрицательное положение, означающее, что оно может появиться немного за пределами области просмотра)
  • анимирует фотографию с помощью API веб-анимации. Ключевые кадры увеличивают изображение от 0 до полной непрозрачности, поворачивая изображение

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

От силы к силе

Разработка API веб-анимации продолжается быстро:

Вывод

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

Я хотел бы видеть ваши исследования в API веб-анимации, особенно на производственных сайтах: дайте мне знать в комментариях ниже!