В 2020 году автор оригинальной статьи решил написать более эффективную библиотеку PJAX, похожую на проект Rezo Zero — Starting Blocks, но так, чтобы легко работать с barbajs. Он понимал, что Starting Blocks легче расширить с помощью настраиваемых функций и их можно сделать более плавными, быстрыми и простыми в использовании. Со временем намерения автора изменились, и он начал замечать, как часто сайты с awwwards.com используют PJAX, но также часто мешают естественному восприятию сайта и браузера.
Многие сайты на первый взгляд выглядели круто, но если вы работали с ними долго, то это была другая история — полосы прокрутки часто переопределялись, предварительное извлечение часто было слишком активным и не оптимизированным для людей без мощного подключения к Интернету, ЦП и/или графических процессоров. К старту курса о Fullstack-разработке на Python делимся переводом обзора библиотеки @okikio/animate от её автора. На КДПВ вы видите первый кадр любопытной анимации из демо к библиотеке, эта анимация работает в закреплённой шапке сайта.
Введение
Из документации MDN:
Web Animations API (WAAPI) позволяет нам создавать анимации и управлять ими с помощью JavaScript. Этот API открывает разработчикам механизм браузерной анимации и лежит в основе реализации анимации и переходов CSS, оставляя возможности для будущих эффектов анимации. Этот API предоставляет один из наиболее эффективных способов анимации в вебе, позволяющий браузеру выполнять собственную внутреннюю оптимизацию без хаков, приведения типов или window.requestAnimationFrame().
Если вы не знаете, что такое библиотека PJAX, я предлагаю посмотреть MoOx/pjax; говоря коротко, PJAX позволяет плавно переходить по страницам, используя запросы Fetch API и отключая элементы DOM.
С помощью Web Animations API мы можем перемещать интерактивные анимации из CSS в JavaScript, отделяя представление от поведения. Нам больше не нужно полагаться на тяжёлые методы DOM, такие как запись свойств CSS и определение классов в элементы для управления направлением воспроизведения.
В отличие от чистого декларативного CSS JavaScript также позволяет нам динамически устанавливать значения: от свойств до длительностей. Web Animations API (далее — WAAPI) может стать идеальным инструментом, чтобы создавать пользовательские библиотеки анимации и интерактивные анимации. Посмотрим, на что он способен!
В оставшейся части этой статьи я иногда буду называть Web Animations API — WAAPI. При поиске ресурсов о Web Animations API вы можете сбиться с пути, введя поисковый запрос «Web Animations API», поэтому, чтобы упростить поиск ресурсов, мы должны принять термин «WAAPI»; расскажите мне, что вы думаете, в комментариях ниже.
На самом деле WAAPI очень легко перепутать с Web Audio API, по этой причине лучше гуглить полное название, этот фрагмент оставлен для ясности о том, что было в оригинале. — прим. ред.
Об @okikio/animate
@okikio/animate — это библиотека анимации для современного веба. Она была вдохновлена animateplus и animejs; библиотека ориентирована на производительность и удобство для разработчиков и работает с Web Animations API для создания плавной анимации, она имеет небольшой размер (~ 5,79 КБ) после минимизации кода и сжатия с gzip.
О разработке
Итак, я решил постепенно улучшать библиотеку, которую собирался создать. Я начал то, что я называю «нативной инициативой», хранящейся в репозитории GitHub okikio/native, — средства представления всех крутых и современных функций с высокой производительностью, совместимостью при небольшом весе.
В рамках нативной инициативы я разработал библиотеку для PJAX — okikio/native. Во время тестирования реального проекта я столкнулся с WAAPI и понял, что библиотек, которые работали бы с ним, просто нет, поэтому я разработал okikio/animate — библиотеку анимации, которая совместима с браузером.
Примечание: это было в 2020 году, примерно в то же время, когда разрабатывалась use-web-animations от wellyshen. Если вы используете react и вам нужны быстрые эффекты, подобные эффектам из animate.css, use-web-animations подойдёт.) Прежде всего, это была простая оболочка, но мало-помалу я разрабатывал её, и теперь она имеет 80% функций зрелых библиотек анимации.
Вы можете прочитать больше о нативной инициативе, а также о библиотеке okikio/native в репозитории okikio/native. Кроме того, вот монорепозиторий, где okikio/native и okikio/animate — это подпакеты.
Постепенно переходим к okikio/animate
У WAAPI очень открытый дизайн. Он функционален сам по себе, но это не самый удобный или интуитивно понятный API, поэтому я разработал okikio/animate, выполняющий роль оболочки вокруг WAAPI и представляющий функции, которые вы знаете и любите из других более зрелых библиотек анимации (вместе с некоторыми новыми функциями) в высокопроизводительный API веб-анимации. Чтобы узнать больше, прочтите README проекта.
Приступим к делу
@okikio/animate создаёт анимацию при помощи экземпляров Animate (оболочки API веб-анимации).
import { Animate } from"@okikio/animate";
new Animate({
target: [/* ... */],
duration: 2000,
// ...
});
Класс Animate получает набор целей для анимации, затем он создаёт список экземпляров Animation WAAPI вместе с основной анимацией (основная анимация — это небольшой экземпляр Animation, который настроен анимировать невидимый элемент: это способ отслеживания хода анимации различных целевых элементов), класс Animate затем воспроизводит каждый экземпляр анимации целевых элементов, включая основную анимацию, так анимации получаются плавными.
Основная анимация предназначена, чтобы гарантировать точность в реализациях WAAPI различных поставщиков браузеров. Она хранится в Animate.prototype.mainAnimation, а экземпляры Animation целевого элемента хранятся в WeakMap, а ключ отображения — KeyframeEffect. Получить доступ к анимации конкретной цели можно так:
Animate.prototype.getAnimation(el)
Не нужно полностью разбираться в сказанном выше, но эти детали помогут понять, что делает okikio/animate. Если вы хотите больше узнать о том, как работает WAAPI, ознакомьтесь с документацией MDN или, если вы хотите узнать больше о библиотеке okikio/animate, я бы посоветовал посмотреть на проект okikio/native на GitHub.
Использование, примеры и демонстрации
По умолчанию создание нового экземпляра Animate сильно раздражает, поэтому я написал функцию animate, которая создаёт новые экземпляры Animate при каждом вызове.
import animate from "@okikio/animate";
// or
import { animate } from "@okikio/animate";
animate({
target: [/* ... */],
duration: 2000,
// ...
});
При работе с okikio/animate для создания анимации вы можете сделать следующее:
import animate from "@okikio/animate";
// Do this if you installed it via the script tag: const { animate } = window.animate;
(async () => {
let [options] = await animate({
target: ".div",
// Units are added automatically for transform CSS properties
translateX: [0, 300],
duration: 2000, // In milliseconds
speed: 2,
});
console.log("The Animation is done...");
})();
Вы также можете поиграть с демонстрацией с элементами управления воспроизведением:
Попробуйте Motion Path:
Также попробуйте разные типы движения, изменив параметры анимации:
Кроме того, я написал сложную демонстрационную страницу с полифиллами:
Исходный код этой демонстрации вы найдёте в файлах animate.ts и animate.pug в репозитории GitHub. И, да, в демоверсии используется Pug, это довольно сложная установка. Я настоятельно рекомендую изучить README.
В нативной инициативе используется Gitpod, поэтому, если вы хотите поиграть с демонстрацией, я рекомендую нажать ссылку «Open in Gitpod», там вся среда уже настроена. На Codepen можно посмотреть ещё несколько примеров из собранной коллекции. Код animejs портируется на okikio/animate практически без проблем.
Я должен, наверное, упомянуть, что для настроек целей анимации @okikio/animate поддерживает ключевые слова target, так и targets. Библиотека объединит оба списка целей в один и для удаления любых повторяющихся целей использует Set. @okikio/animate поддерживает функции как параметры анимации, поэтому вы можете использовать смещение, как в animejs. (Примечание: порядок аргументов другой, смотрите раздел «Animation Options & CSS Properties as Methods» файла README.)
Ограничения
okikio/animate не совершенен, ничто не совершенно, и, поскольку Web Animations API — это живой стандарт, который постоянно совершенствуется, okikio/animate самому ещё есть куда расти. Учитывая это, я постоянно пытаюсь улучшить библиотеку и буду рад вашему участию, поэтому, пожалуйста, откройте новую проблему (Issue), создайте пул-реквест или мы можем обсудить [в оригинале здесь ещё одна ссылка на README, а в переводе на Github Discussions] библиотеку на GitHub.
Первое ограничение заключается в том, что у библиотеки нет встроенного таймлайна. Тому есть несколько причин:
У меня не хватило времени. Я ещё только студент, и у меня нет времени на разработку.
Я не думал, что нужен формальный таймлайн, так как поддерживалось async/await. Кроме того, я добавил timelineOffset в качестве опции анимации, если кому-то когда-нибудь понадобится создать что-то, похожее на таймлайн, в animejs.
Я хотел сделать okikio/animate как можно меньшего размера.
Поскольку скоро появятся групповые и последовательные эффекты, я подумал, что будет лучше оставить пакет маленьким, пока не возникнет реальная необходимость увеличения размера. В связи с этим я настоятельно рекомендую прочитать серию статей Дэниела К. Уилсона о WAAPI, особенно четвёртую часть, в которой рассматриваются групповые эффекты и эффекты последовательности.
Ещё одно ограничение @okikio/animate заключается в том, что в нём отсутствует поддержка настраиваемых сглаживаний. Но вы можете ознакомиться с предложением Джейка Арчибальда по сглаживанию ворклета. Он описывает несколько стандартов, которые обсуждаются в настоящее время. Я предпочитаю его предложение, так как оно самое простое в реализации, не говоря уже о том, что оно самое элегантное. А пока я черпаю вдохновение из статьи Кирилла Васильцова об анимации Spring при помощи WAAPI и планирую встроить в библиотеку что-то подобное.
Последнее ограничение заключается в том, что @okikio/animate поддерживает только автоматические единицы для функций преобразования, например translateX, translate, scale, skew и т. д. В @okikio/animate@2.2.0 его больше нет, но всё ещё существуют некоторые ограничения в смысле цветовых свойств CSS. Чтобы узнать больше, посмотрите релиз на GitHub.
Вот пример:
animate({
targets: [".div", document.querySelectorAll(".el")],
// By default "px", will be applied
translateX: 300,
left: 500,
margin: "56 70 8em 70%",
// "deg" will be applied to rotate instead of px
rotate: 120,
// No units will be auto applied
color: "rgb(25, 25, 25)",
"text-shadow": "25px 5px 15px rgb(25, 25, 25)"
});
Заглядывая в будущее
Реализации некоторых функций, таких как ScrollTimeline, уже не за горами. Я не уверен, что кто-нибудь знает, когда она появится, но после ScrollTimeline в Chrome Canary 92 с уверенностью можно сказать, что шансы на релиз в ближайшем будущем представляются достаточно большими. Я встроил опцию анимации таймлайна в okikio/animate, чтобы идтив ногу со временем. Вот пример:
Спасибо Bramus за вдохновение для этого демо! Чтобы посмотреть его, вам может понадобиться Canary-версия Chrome или нужно включить функции Experimental Web Platform в Chrome Flags. В Firefox демонстрация работает отлично. На случай, если вы хотите узнать больше о ScrollTimeline, Брамус написал об этом отличную статью. Я также предлагаю прочитать статью Google Developers о Animation Worklets.
Я надеюсь сделать библиотеку ещё меньше. Сейчас она весит ~5,79 КБ, размер кажется большим, по крайней мере мне. В обычной ситуации я использовал бы bundlephobia, но у него проблемы со сборкой проекта, поэтому, если вы хотите узнать точный размер, я предлагаю работать с bundle.js.org, потому что он фактически собирает код локально, в вашем браузере. Этот сайт я создал специально для проверки размера пакета @okikio/animate, но обратите внимание, что он не так точен, как bundlephobia.
Полифиллы
Одна из предыдущих демонстраций показывает полифиллы в действии. Для поддержки таймлайнов вам понадобится web-animations-next.min.js из web-animations-js. Для других современных функций требуется конструктор KeyframeEffect.
Полифилл использует JavaScript, чтобы проверить, поддерживается ли KeyframeEffect, и, если нет, полифилл загружается и выполняет свою задачу. Не применяйте async/defer к полифиллу, иначе он не будет работать так, как вы ожидаете. Вам также понадобятся полифиллы Map, Set и Promise.
<html>
<head>
<!-- Async -->
<script src="https://cdn.polyfill.io/v3/polyfill.min.js?features=default,es2015,es2018,Array.prototype.includes,Map,Set,Promise" async></script>
<!-- NO Async/Defer -->
<script src="./js/webanimation-polyfill.min.js"></script>
</head>
<body>
<!-- Content -->
</body>
</html>
Если проект собирается для ES6+, я настоятельно рекомендую использовать esbuild для транспиляции, пакетирования и минификации. В случае ES5 предлагаю использовать esbuild (с выключенным minify), Typescript и terser; на данный момент это даёт самую быструю установку для транспиляции в ES5, она быстрее и надёжнее, чем babel. Чтобы узнать больше, смотрите Gulpfile из демонстрации.
Заключение
@okikio/animate — это оболочка вокруг Web Animations API (WAAPI), позволяющая вам использовать все функции, которые вам нравятся, из animejs и других библиотек анимации, в небольшом и лаконичном пакете.
Эта статья и живой пример автора показывают, что обучение в ВУЗах или работу возможно совмещать с разработкой ПО и получением знаний в этой области в целом. Если вы хотите понимать не только фронтенд-разработку, но также есть желание работать с вебом изнутри, то вы можете присмотреться к нашему курсу о Fullstack-разработке на Python, где студенты на практике изучают не только разработку, но и знакомятся с DevOps.
Узнайте, как прокачаться и в других специальностях или освоить их с нуля:
Другие профессии и курсы
ПРОФЕССИИ
КУРСЫ