Представьте себе: вы присоединяетесь к новому проекту, погружаетесь в кодовую базу и в течение первых нескольких часов обнаруживаете что-то до боли знакомое. В таблицах стилей вы найдете несколько определений @keyframes для одних и тех же базовых анимаций. Три разных эффекта плавного появления, два или три варианта слайдов, несколько анимаций масштабирования и как минимум две разные анимации вращения, ну а почему бы и нет? @keyframes пульс { от { масштаб: 1; } до { масштаб: 1,1; } }
@keyframes больший импульс { 0%, 20%, 100% { масштаб: 1; } 10%, 40% { масштаб: 1,2; } }
Если этот сценарий звучит знакомо, вы не одиноки. По моему опыту работы с различными проектами, один из самых последовательных быстрых результатов, которые я могу добиться, — это консолидация и стандартизация ключевых кадров. Это стало настолько надежным шаблоном, что теперь я с нетерпением жду этой очистки как одной из своих первых задач в любой новой базе кода. Логика хаоса Эта избыточность имеет смысл, если задуматься. В повседневной работе мы все используем одни и те же фундаментальные анимации: затухание, скольжение, масштабирование, вращение и другие распространенные эффекты. Эти анимации довольно просты, и для выполнения работы легко создать быстрое определение @keyframes. Без централизованной системы анимации разработчики, естественно, пишут эти ключевые кадры с нуля, не подозревая, что подобные анимации уже существуют где-то в кодовой базе. Это особенно распространено при работе с компонентными архитектурами (что сегодня делает большинство из нас), поскольку команды часто работают параллельно над разными частями приложения. Результат? Анимационный хаос. Маленькая проблема Наиболее очевидными проблемами дублирования ключевых кадров являются напрасная трата времени на разработку и ненужное раздувание кода. Несколько определений ключевых кадров означают несколько мест для обновления при изменении требований. Вам нужно настроить время анимации затухания? Вам нужно будет отследить каждый экземпляр в вашей кодовой базе. Хотите стандартизировать функции замедления? Удачи в поиске всех вариантов. Такое увеличение количества точек обслуживания делает даже простое обновление анимации трудоемкой задачей. Большая проблема Дублирование ключевых кадров создает гораздо более коварную проблему, скрывающуюся под поверхностью: ловушку глобальной области видимости. Даже при работе с компонентной архитектурой ключевые кадры CSS всегда определяются в глобальной области видимости. Это означает, что все ключевые кадры применяются ко всем компонентам. Всегда. Да, ваша анимация не обязательно использует ключевые кадры, которые вы определили в своем компоненте. Он использует последние ключевые кадры, соответствующие тому же имени, которое было загружено в глобальную область видимости. Пока все ваши ключевые кадры идентичны, это может показаться незначительной проблемой. Но в тот момент, когда вы захотите настроить анимацию для конкретного варианта использования, у вас возникнут проблемы или, что еще хуже, вы станете их причиной. Либо ваша анимация не будет работать, потому что другой компонент загружается после вашего, перезаписывая ваши ключевые кадры, либо ваш компонент загружается последним и случайно меняет поведение анимации для каждого другого компонента, использующего имя этого ключевого кадра, и вы можете даже не осознавать этого. Вот простой пример, демонстрирующий проблему: .компонент-один { /* стили компонентов */ анимация: импульс 1 с, плавность входа и выхода, бесконечная альтернатива; }
/* это определение @keyframes не будет работать */ @keyframes пульс { от { масштаб: 1; } до { масштаб: 1,1; } }
/* далее в коде... */
.компонент-два { /* стили компонентов */ анимация: импульс 1 с, легкость входа и выхода бесконечна; }
/* эти ключевые кадры будут применяться к обоим компонентам */ @keyframes пульс { 0%, 20%, 100% { масштаб: 1; } 10%, 40% { масштаб: 1,2; } }
Оба компонента используют одно и то же имя анимации, но второе определение @keyframes перезаписывает первое. Теперь и первый, и второй компоненты будут использовать вторые ключевые кадры, независимо от того, какой компонент какие ключевые кадры определил. См. токены Pen Keyframes — демо 1 [разветвление] Амита Шина. Худшая часть? Это часто отлично работает при локальной разработке, но загадочным образом дает сбой в рабочей среде, когда процессы сборки изменяют порядок загрузки ваших таблиц стилей. В итоге вы получаете анимации, которые ведут себя по-разному в зависимости от того, какие компоненты загружаются и в какой последовательности. Решение: унифицированные ключевые кадры Ответ на этот хаос на удивление прост: предопределенные динамические ключевые кадры хранятся в общей таблице стилей. Вместо того, чтобы позволить каждому компоненту определять свою собственную анимацию, мы создаем централизованные ключевые кадры, которые хорошо документированы и просты в использовании.использовать, обслуживать и адаптировать к конкретным потребностям вашего проекта. Думайте об этом как о токенах ключевых кадров. Точно так же, как мы используем токены для цветов и интервалов, а многие из нас уже используют токены для свойств анимации, таких как функции длительности и замедления, почему бы не использовать токены и для ключевых кадров? Этот подход может естественным образом интегрироваться с любым текущим рабочим процессом токена проектирования, который вы используете, одновременно решая как небольшую проблему (дублирование кода), так и большую проблему (конфликты глобальной области действия) за один раз. Идея проста: создать единый источник правды для всех наших общих анимаций. Эта общая таблица стилей содержит тщательно созданные ключевые кадры, которые охватывают шаблоны анимации, которые фактически используются в нашем проекте. Больше не нужно гадать, существует ли где-нибудь в нашей кодовой базе анимация затухания. Больше не нужно случайно перезаписывать анимацию из других компонентов. Но вот ключ: это не просто статичные анимации копирования и вставки. Они спроектированы так, чтобы быть динамичными и настраиваемыми с помощью пользовательских свойств CSS, что позволяет нам поддерживать согласованность, сохраняя при этом гибкость в адаптации анимации к конкретным случаям использования, например, если вам нужна немного более крупная «импульсная» анимация в одном месте. Создание первого токена ключевых кадров Одним из первых результатов, с которыми нам следует разобраться, является анимация «затухания». В одном из моих недавних проектов я нашел более дюжины отдельных определений постепенного появления, и да, все они просто анимировали непрозрачность от 0 до 1. Итак, давайте создадим новую таблицу стилей, назовем ее kf-tokens.css, импортируем ее в наш проект и разместим внутри нее ключевые кадры с соответствующими комментариями. /* ключевые кадры-токены.css */
/* * Fade In - постепенное исчезновение анимации входа. * Использование: анимация: kf-fade-in, замедление 0,3 с; */ @keyframes kf-fade-in { от { непрозрачность: 0; } до { непрозрачность: 1; } }
Это единственное объявление @keyframes заменяет все эти разбросанные по всей нашей кодовой базе анимации плавного появления. Чистый, простой и глобально применимый. И теперь, когда у нас определен этот токен, мы можем использовать его из любого компонента нашего проекта: .модальный { анимация: kf-fade-in, замедление 0,3 с; }
.tooltip { анимация: kf-fade-in с задержкой 0,2 с; }
.уведомление { анимация: kf-fade-in, замедление 0,5 с; }
См. токены Pen Keyframes — демо 2 [раздвоение] Амита Шина. Примечание. Мы используем префикс kf- во всех именах @keyframes. Этот префикс служит пространством имен, которое предотвращает конфликты имен с существующими анимациями в проекте и сразу дает понять, что эти ключевые кадры взяты из нашего файла токенов ключевых кадров. Создание динамического слайда Ключевые кадры kf-fade-in работают отлично, потому что они просты и в них мало места, чтобы что-то испортить. Однако в других анимациях нам нужно быть гораздо более динамичными, и здесь мы можем использовать огромную мощь пользовательских свойств CSS. Именно здесь токены ключевых кадров действительно хороши по сравнению с разрозненными статическими анимациями. Давайте возьмем распространенный сценарий: «скользящую» анимацию. Но проскользнуть откуда? 100 пикселей справа? 50% слева? Должно ли оно входить сверху экрана? Или, может быть, всплывать снизу? Так много возможностей, но вместо того, чтобы создавать отдельные ключевые кадры для каждого направления и каждого варианта, мы можем создать один гибкий токен, который адаптируется ко всем сценариям: /* * Slide In — направленная анимация слайда. * Используйте --kf-slide-from для управления направлением * По умолчанию: сдвигается слева (-100%). * Использование: * анимация: плавное выдвижение kf-in и выдвижение за 0,3 с; * --kf-slide-from: -100px 0; // слайд слева * --kf-slide-from: 100px 0; // слайд справа * --kf-slide-from: 0 -50px; // слайд сверху */
@keyframes kf-slide-in { от { перевести: var(--kf-slide-from, -100% 0); } до { перевести: 0 0; } }
Теперь мы можем использовать этот единственный токен @keyframes для любого направления слайда, просто изменив пользовательское свойство --kf-slide-from: .сайдбар { анимация: плавное выдвижение kf-slide-in (0,3 с); /* Использует значение по умолчанию: слайды слева */ }
.уведомление { анимация: плавное выдвижение kf-slide-in (0,4 с); --kf-slide-from: 0 -50px; /* слайд сверху */ }
.модальный { анимация: kf-нарастание 0,5 с, kf-slide-in 0,5 с кубической Безье (0,34, 1,56, 0,64, 1); --kf-slide-from: 50px 50px; /* слайд из правого нижнего угла */ }
Такой подход дает нам невероятную гибкость при сохранении последовательности. Одно объявление ключевого кадра, безграничные возможности. См. токены Pen Keyframes — демо 3 [раздвоение] Амита Шина. И если мы хотим сделать нашу анимацию еще более гибкой, допуская также эффекты «выдвижения», мы можемпросто добавьте пользовательское свойство --kf-slide-to, подобное тому, что мы увидим в следующем разделе. Ключевые кадры двунаправленного масштабирования Еще одна распространенная анимация, которая дублируется в разных проектах, — это эффекты масштабирования. Будь то небольшое увеличение для всплывающих сообщений, резкое увеличение для модальных окон или плавное уменьшение для заголовков, анимация масштабирования присутствует повсюду. Вместо того, чтобы создавать отдельные ключевые кадры для каждого значения масштаба, давайте создадим один гибкий набор ключевых кадров kf-zoom:
/* * Zoom - масштабировать анимацию * Используйте --kf-zoom-from и --kf-zoom-to для управления значениями масштаба. * По умолчанию: масштабирование от 80% до 100% (от 0,8 до 1). * Использование: * анимация: замедление kf-zoom 0,2 с; * --kf-zoom-from: 0,5; --kf-zoom-to: 1; // масштабирование от 50% до 100% * --kf-zoom-from: 1; --kf-zoom-to: 0; // масштабирование от 100% до 0% * --kf-zoom-from: 1; --kf-zoom-to: 1.1; // масштабирование от 100% до 110% */
@keyframes kf-zoom { от { масштаб: var(--kf-zoom-from, 0,8); } до { масштаб: var(--kf-zoom-to, 1); } }
С помощью одного определения мы можем добиться любого изменения масштаба, которое нам нужно: .тост { анимация: kf-slide-in 0,2с, kf-zoom замедление 0,4 с; --kf-slide-from: 0 100%; /* слайд сверху */ /* Использует масштаб по умолчанию: масштабируется от 80% до 100% */ }
.модальный { анимация: kf-zoom 0,3 с кубический-безье (0,34, 1,56, 0,64, 1); --kf-zoom-from: 0; /* резкое масштабирование от 0% до 100% */ }
.heading { анимация: кф-нарастание 2 с, kf-zoom 2s легкость; --kf-zoom-from: 1.2; --kf-zoom-to: 0,8; /* плавное уменьшение */ }
Значение по умолчанию 0,8 (80%) идеально подходит для большинства элементов пользовательского интерфейса, таких как всплывающие сообщения и карточки, но при этом его легко настроить для особых случаев. См. токены Pen Keyframes — демо 4 [разветвление] Амита Шина. Возможно, вы заметили кое-что интересное в последних примерах: мы комбинируем анимацию. Одним из ключевых преимуществ работы с токенами @keyframes является то, что они предназначены для полной интеграции друг с другом. Эта плавная композиция создана намеренно, а не случайно. Позже мы обсудим композицию анимации более подробно, включая моменты, когда они могут стать проблематичными, но большинство комбинаций просты и легко реализуются. Примечание. Во время написания этой статьи, а может быть, и в результате ее написания, я обнаружил, что переосмыслил всю идею анимации входа. Нужны ли они нам вообще, несмотря на все последние достижения в области CSS? К счастью, Адам Аргайл исследовал те же вопросы и блестяще изложил их в своем блоге. Это не противоречит тому, что здесь написано, но представляет собой подход, который стоит рассмотреть, особенно если ваши проекты сильно полагаются на входную анимацию. Непрерывная анимация В то время как входные анимации, такие как «затухание», «скольжение» и «масштабирование», происходят один раз, а затем останавливаются, непрерывные анимации повторяются бесконечно, чтобы привлечь внимание или указать на продолжающуюся активность. Две наиболее распространенные непрерывные анимации, с которыми я сталкиваюсь, — это «вращение» (для загрузки индикаторов) и «импульс» (для выделения важных элементов). Эти анимации создают уникальные проблемы при создании токенов ключевых кадров. В отличие от входных анимаций, которые обычно переходят из одного состояния в другое, непрерывные анимации должны иметь широкие возможности настройки шаблонов поведения. Спин-доктор Кажется, что в каждом проекте используется несколько анимаций вращения. Некоторые вращаются по часовой стрелке, другие против часовой стрелки. Некоторые делают один поворот на 360 градусов, другие делают несколько поворотов для более быстрого эффекта. Вместо того, чтобы создавать отдельные ключевые кадры для каждого варианта, давайте создадим один гибкий вариант, который будет обрабатывать все сценарии:
/* * Spin - анимация вращения * Используйте --kf-spin-from и --kf-spin-to для управления диапазоном вращения. * Используйте --kf-spin-turns для управления величиной вращения. * По умолчанию: поворот от 0 до 360 градусов (1 полный оборот). * Использование: * анимация: kf-spin 1s линейная бесконечность; * --kf-spin-turns: 2; // 2 полных оборота * --kf-spin-from: 0deg; --kf-spin-to: 180 градусов; // половина оборота * --kf-spin-from: 0deg; --kf-spin-to: -360 градусов; // против часовой стрелки */
@keyframes kf-spin { от { вращать: вар (--kf-spin-from, 0deg); } до { Rotate: Calc(var(--kf-spin-from, 0deg) + var(--kf-spin-to, 360deg) * var(--kf-spin-turns, 1)); } }
Теперь мы можем создать любой вариант вращения, который нам нравится:
.loading-спиннер { анимация: kf-spin 1s линейная бесконечность; /* Использует значение по умолчанию: поворот от 0 до 360 градусов */ }
.fast-loader { анимация: бесконечная альтернатива kf-spin 1.2s с легкостью входа и выхода; --kf-спин-повороты: 3; /* 3 полных оборота для каждого направления за цикл*/ }
.steped-reverse { анимация: kf-spin 1,5 с, шаги (8) бесконечно; --kf-spin-to: -360 градусов; /* против часовой стрелки */ }
.тонкое-покачивание { анимация: бесконечная альтернатива kf-spin 2s easy-in-out; --kf-spin-from: -16град; --kf-spin-to: 32 град; /* покачивание на 36 градусов: от -18 до +18 градусов */ }
См. токены Pen Keyframes — демо 5 [разветвление] Амита Шина. Прелесть этого подхода в том, что одни и те же ключевые кадры используются для загрузки счетчиков, вращения значков, эффектов покачивания и даже сложных многоповоротных анимаций. Парадокс пульса Импульсная анимация сложнее, поскольку она может «импульсировать» различные свойства. Некоторые пульсируют масштаб, другие пульсируют непрозрачность, а некоторые пульсируют такие свойства цвета, как яркость или насыщенность. Вместо того, чтобы создавать отдельные ключевые кадры для каждого свойства, мы можем создавать ключевые кадры, которые работают с любым свойством CSS. Вот пример ключевого кадра импульса с параметрами масштаба и непрозрачности:
/* * Пульс - пульсирующая анимация * Используйте --kf-pulse-scale-from и --kf-pulse-scale-to для управления диапазоном шкалы. * Используйте --kf-pulse-opacity-from и --kf-pulse-opacity-to для управления диапазоном непрозрачности. * По умолчанию: нет пульса (все значения 1) * Использование: * анимация: бесконечная альтернатива kf-pulse 2s easy-in-out; * --kf-pulse-scale-from: 0,95; --kf-pulse-scale-to: 1,05; // масштабируем импульс * --kf-pulse-opacity-from: 0.7; --kf-pulse-opacity-to: 1; // импульс непрозрачности */
@keyframes kf-pulse { от { масштаб: var(--kf-pulse-scale-from, 1); непрозрачность: var(--kf-pulse-opacity-from, 1); } до { масштаб: var(--kf-pulse-scale-to, 1); непрозрачность: var (--kf-pulse-opacity-to, 1); } }
Это создает гибкий импульс, который может анимировать несколько свойств: .призыв к действию { анимация: бесконечная альтернатива kf-pulse 0,6 с; --kf-pulse-opacity-from: 0,5; /* импульс непрозрачности */ }
.notification-точка { анимация: kf-pulse 0,6 с, плавность входа и выхода, бесконечная альтернатива; --kf-pulse-scale-from: 0,9; --kf-pulse-scale-to: 1.1; /* масштабируемый импульс */ }
.text-highlight { анимация: kf-pulse 1,5 с, плавность хода бесконечна; --kf-pulse-scale-from: 0,8; --kf-pulse-opacity-from: 0,2; /* импульс масштабирования и непрозрачности */ }
См. токены Pen Keyframes — демо 6 [раздвоение] Амита Шина. Этот единственный ключевой кадр kf-pulse может обрабатывать все: от едва заметного привлечения внимания до ярких ярких моментов, и при этом его легко настроить. Расширенное замедление Одна из замечательных особенностей использования токенов ключевых кадров — это то, насколько легко расширить нашу библиотеку анимации и предоставить эффекты, которые большинство разработчиков не стали бы писать с нуля, например эластичность или отскок. Вот пример простого токена ключевых кадров «bounce», который использует пользовательское свойство --kf-bounce-from для управления высотой прыжка. /* * Bounce - подпрыгивающая анимация входа * Используйте --kf-bounce-from для управления высотой прыжка. * По умолчанию: скачок со 100vh (за кадром) * Использование: * анимация: облегчение kf-bounce 3s; * --kf-bounce-from: 200px; // прыжок с высоты 200 пикселей */
@keyframes kf-bounce { 0% { транслировать: 0 Calc(var(--kf-bounce-from, 100vh) * -1); }
34% { транслировать: 0 Calc(var(--kf-bounce-from, 100vh) * -0.4); }
55% { транслировать: 0 Calc(var(--kf-bounce-from, 100vh) * -0.2); }
72% { транслировать: 0 Calc(var(--kf-bounce-from, 100vh) * -0.1); }
85% { транслировать: 0 Calc(var(--kf-bounce-from, 100vh) * -0.05); }
94% { транслировать: 0 Calc(var(--kf-bounce-from, 100vh) * -0,025); }
99% { транслировать: 0 Calc(var(--kf-bounce-from, 100vh) * -0.0125); }
22%, 45%, 64%, 79%, 90%, 97%, 100% { перевести: 0 0; функция синхронизации анимации: легкость; } }
Анимации вроде «эластичности» немного сложнее из-за вычислений внутри ключевых кадров. Нам нужно определить --kf-elastic-from-X и --kf-elastic-from-Y отдельно (оба не являются обязательными), и вместе они позволят нам создать эластичный вход из любой точки экрана.
/* * Elastic In - эластичная анимация входа * Используйте --kf-elastic-from-X и --kf-elastic-from-Y для управления начальной позицией. * По умолчанию: вход сверху по центру (0, -100vh). * Использование: * анимация: kf-elastic-in 2s easy-in-out оба; * --kf-elastic-from-X: -50px; * --kf-elastic-from-Y: -200px; // входим из (-50px, -200px) */
@keyframes kf-elastic-in { 0% { перевести: Calc(var(--kf-elastic-from-X, -50vw) * 1) Calc(var(--kf-elastic-from-Y, 0px) * 1); }
16% { перевод: Calc(var(--kf-elastic-from-X, -50vw) * -0.3227) Calc(var(--kf-elastic-from-Y, 0px) * -0.3227); }
28% { перевести: Calc(var(--kf-elastic-from-X, -50vw) * 0,1312)Calc(var(--kf-elastic-from-Y, 0px) * 0,1312); }
44% { перевод: Calc(var(--kf-elastic-from-X, -50vw) * -0.0463) Calc(var(--kf-elastic-from-Y, 0px) * -0.0463); }
59% { транслировать: Calc(var(--kf-elastic-from-X, -50vw) * 0,0164) Calc(var(--kf-elastic-from-Y, 0px) * 0,0164); }
73% { транслировать: Calc(var(--kf-elastic-from-X, -50vw) * -0.0058) Calc(var(--kf-elastic-from-Y, 0px) * -0.0058); }
88% { транслировать: Calc(var(--kf-elastic-from-X, -50vw) * 0,0020) Calc(var(--kf-elastic-from-Y, 0px) * 0,0020); }
100% { перевести: 0 0; } }
Такой подход позволяет легко повторно использовать и настраивать расширенные ключевые кадры в нашем проекте, просто изменив одно пользовательское свойство.
.bounce-and-zoom { анимация: kf-bounce 3s легкость, кф-зум 3s линейный; --kf-zoom-from: 0; }
.bounce-and-slide { анимационная композиция: добавить; /* Обе анимации используют трансляцию */ анимация: kf-bounce 3s легкость, kf-выдвижной механизм 3s; --kf-slide-from: -200px; }
.elastic-in { анимация: kf-elastic-in 2s, легко вставить оба; }
См. токены Pen Keyframes — демо 7 [разветвление] Амита Шина. До этого момента мы видели, как можно разумно и эффективно объединить ключевые кадры. Конечно, вы можете захотеть настроить что-то так, чтобы оно лучше соответствовало потребностям вашего проекта, но мы рассмотрели примеры нескольких распространенных анимаций и случаев повседневного использования. И благодаря этим токенам ключевых кадров у нас теперь есть мощные строительные блоки для создания согласованных и легко поддерживаемых анимаций во всем проекте. Больше никаких дублированных ключевых кадров и конфликтов глобальной области действия. Просто чистый и удобный способ удовлетворить все наши потребности в анимации. Но реальный вопрос заключается в следующем: как нам соединить эти строительные блоки вместе? Собираем все вместе Мы увидели, что объединить основные токены ключевых кадров очень просто. Ничего особенного нам не нужно, кроме как определить первую анимацию, определить вторую, задать нужные переменные и всё. /* Постепенное появление + скольжение */ .тост { анимация: kf-нарастание 0,4 с, kf-slide-in 0,4 с кубической Безье (0,34, 1,56, 0,64, 1); --kf-slide-from: 0 40px; }
/* Увеличение + постепенное увеличение */ .модальный { анимация: kf-нарастание 0,3 с, kf-zoom 0,3 с кубического Безье (0,34, 1,56, 0,64, 1); --kf-zoom-from: 0,7; --kf-zoom-to: 1; }
/* Скольжение + импульс */ .уведомление { анимация: кф-скольжение 0,5с, kf-pulse 1,2 с, бесконечная альтернатива с легким входом и выходом; --kf-slide-from: -100px 0; --kf-pulse-scale-from: 0,95; --kf-pulse-scale-to: 1,05; }
Эти комбинации прекрасно работают, поскольку каждая анимация нацелена на разные свойства: непрозрачность, преобразование (перемещение/масштабирование) и т. д. Но иногда возникают конфликты, и нам нужно знать, почему и как с ними справиться. Когда две анимации пытаются анимировать одно и то же свойство (например, обе анимации масштабирования или обе анимации непрозрачности), результат будет не таким, как вы ожидаете. По умолчанию к этому свойству фактически применяется только одна анимация — последняя в списке анимаций. Это ограничение того, как CSS обрабатывает несколько анимаций для одного и того же свойства. Например, это не будет работать должным образом, поскольку будет применяться только анимация kf-pulse. .bad-combo { анимация: kf-zoom 0,5 с вперед, kf-импульс 1,2 с, бесконечный попеременный; --kf-zoom-from: 0,5; --kf-zoom-to: 1.2; --kf-pulse-scale-from: 0,8; --kf-pulse-scale-to: 1.1; }
Дополнение к анимации Самый простой и прямой способ обработки нескольких анимаций, влияющих на одно и то же свойство, — использовать свойство анимации-композиции. В последнем примере выше анимация kf-pulse заменяет анимацию kf-zoom, поэтому мы не увидим начального масштабирования и не получим ожидаемого масштаба 1,2. Устанавливая добавляемую анимационную композицию, мы сообщаем браузеру объединить обе анимации. Это дает нам желаемый результат. .компонент-два { анимационная композиция: добавить; }
См. токены Pen Keyframes — демо 8 [разветвление] Амита Шина. Этот подход хорошо работает в большинстве случаев, когда мы хотим объединить эффекты одного и того же свойства. Это также полезно, когда нам нужно объединить анимацию со значениями статических свойств. Например, если у нас есть элемент, который использует свойство перевода для позиционирования его именно там, где мы хотим, а затем мы хотим анимировать его с помощью ключевых кадров kf-slide-in, мы получим неприятный видимый прыжок без анимации-композиции. См. токены Pen Keyframes — демо 9 [раздвоение] Амита Шина. Если добавить анимационную композицию, анимация плавно сочетается с существующейTransform, чтобы элемент оставался на месте и анимировался так, как ожидалось. Анимация Другой способ обработки нескольких анимаций — «пошатать» их, то есть запустить вторую анимацию немного позже завершения первой. Это решение не подходит для всех случаев, но оно полезно, когда у нас есть входная анимация, за которой следует непрерывная анимация. /* появление + импульс непрозрачности */ .уведомление { анимация: kf-fade-in 2s, kf-pulse 0,5 с 2 с плавность входа-выхода бесконечная смена; --kf-pulse-opacity-to: 0,5; }
См. токены Pen Keyframes — демо 10 [раздвоение] Амита Шина. Заказ имеет значение Большая часть анимаций, с которыми мы работаем, использует свойство Transform. В большинстве случаев это просто удобнее. Он также имеет преимущество в производительности, поскольку анимацию преобразования можно ускорять с помощью графического процессора. Но если мы используем преобразования, нам нужно признать, что порядок, в котором мы выполняем преобразования, имеет значение. Много. До сих пор в наших ключевых кадрах мы использовали отдельные преобразования. Согласно спецификациям, они всегда применяются в фиксированном порядке: сначала элемент перемещается, затем вращается, затем масштабируется. Это имеет смысл и именно этого ожидает большинство из нас. Однако если мы используем свойство Transform, порядок написания функций соответствует порядку их применения. В этом случае, если мы переместим что-то на 100 пикселей по оси X, а затем повернём на 45 градусов, это не то же самое, что сначала повернуть это на 45 градусов, а затем переместить на 100 пикселей. /* Розовый квадрат: сначала переместите, затем поверните */ .пример-один { преобразование: TranslateX (100 пикселей) вращать (45 градусов); }
/* Зеленый квадрат: сначала поверните, затем переместите */ .пример-два { преобразование: поворот (45 градусов) переводX (100 пикселей); }
См. токены Pen Keyframes — демо 11 [разветвление] Амита Шина. Но в соответствии с порядком преобразования все отдельные преобразования — все, что мы использовали для токенов ключевых кадров — происходят до функций преобразования. Это означает, что все, что вы установили в свойстве Transform, произойдет после анимации. Но если вы установите, например, перевод вместе с ключевыми кадрами kf-spin, перевод произойдет до анимации. Еще не запутались?! Это приводит к ситуациям, когда статические значения могут вызывать разные результаты для одной и той же анимации, как в следующем случае:
/* Общая анимация для обоих счетчиков */ .спиннер { анимация: kf-spin 1s линейная бесконечность; }
/* Розовый счетчик: перевод перед поворотом (индивидуальное преобразование) */ .spinner-pink { перевести: 100% 50%; }
/* Зеленый счетчик: повернуть, затем переместить (порядок функций) */ .spinner-green { трансформировать: транслировать(100%, 50%); }
См. токены Pen Keyframes — демо 12 [разветвление] Амита Шина. Вы можете видеть, что первый спиннер (розовый) получает перемещение, которое происходит перед вращением kf-spin, поэтому он сначала перемещается на свое место, а затем вращается. Второй счетчик (зеленый) получает функцию перевода(), которая происходит после отдельного преобразования, поэтому элемент сначала вращается, затем перемещается относительно своего текущего угла, и мы получаем эффект широкой орбиты. Нет, это не ошибка. Это всего лишь одна из тех вещей, которые нам нужно знать о CSS и иметь в виду при работе с несколькими анимациями или несколькими преобразованиями. При необходимости вы также можете создать дополнительный набор ключевых кадров kf-spin-alt, которые вращают элементы с помощью функции Rotate(). Уменьшенное движение И пока мы говорим об альтернативных ключевых кадрах, мы не можем игнорировать опцию «без анимации». Одним из самых больших преимуществ использования токенов ключевых кадров является то, что специальные возможности могут быть встроены, и это на самом деле довольно легко сделать. Разрабатывая наши ключевые кадры с учетом доступности, мы можем гарантировать, что пользователи, предпочитающие ограниченное движение, получат более плавный и менее отвлекающий опыт без дополнительной работы или дублирования кода. Точное значение слова «Уменьшенное движение» может немного меняться от одной анимации к другой и от проекта к проекту, но вот несколько важных моментов, которые следует иметь в виду: Отключение ключевых кадров Хотя некоторые анимации можно смягчить или замедлить, есть другие, которые должны полностью исчезнуть, когда требуется уменьшить движение. Хорошим примером является пульсирующая анимация. Чтобы убедиться, что эти анимации не выполняются в режиме уменьшенного движения, мы можем просто обернуть их в соответствующий медиа-запрос.
@media (предпочитает уменьшение движения: нет предпочтений) { @keyfrmaes kf-pulse { от { масштаб: var(--kf-pulse-scale-from, 1); непрозрачность: var(--kf-pulse-opacity-from, 1); } до { масштаб: var(--kf-pulse-scale-to, 1); непрозрачность:var(--kf-pulse-opacity-to, 1); } } }
Это гарантирует, что пользователи, которые установили для параметра «Уменьшение движения» значение «Уменьшение», не увидят анимацию и получат опыт, соответствующий их предпочтениям. Мгновенный вход Есть некоторые ключевые кадры, которые мы не можем просто удалить, например, анимацию входа. Ценность должна измениться, должна оживиться; в противном случае элемент не будет иметь правильных значений. Но при замедленном движении этот переход от исходного значения должен быть мгновенным. Чтобы добиться этого, мы определим дополнительный набор ключевых кадров, в которых значение сразу же переходит в конечное состояние. Они станут нашими ключевыми кадрами по умолчанию. Затем мы добавим обычные ключевые кадры в медиа-запрос, чтобы для параметра «предпочтение-уменьшение движения» было установлено значение «нет предпочтений», как и в предыдущем примере. /* мгновенно появляется для уменьшения движения */ @keyframes kf-zoom { от, до { масштаб: var(--kf-zoom-to, 1); } }
@media (предпочитает уменьшение движения: нет предпочтений) { /* Исходные ключевые кадры масштабирования */ @keyframes kf-zoom { от { масштаб: var(--kf-zoom-from, 0,8); } до { масштаб: var(--kf-zoom-to, 1); } } }
Таким образом, пользователи, предпочитающие ограниченное движение, увидят, что элемент мгновенно появляется в конечном состоянии, а все остальные получают анимированный переход. Мягкий подход Бывают случаи, когда нам хочется сохранить какое-то движение, но гораздо мягче и спокойнее, чем исходная анимация. Например, мы можем заменить вход отскока плавным появлением.
@keyframes kf-bounce { /* Мягкое постепенное появление для уменьшения движения */ }
@media (предпочитает уменьшение движения: нет предпочтений) { @keyframes kf-bounce { /* Исходные ключевые кадры отскока */ } }
Теперь пользователи с включенным ограничением движения по-прежнему получают ощущение внешнего вида, но без интенсивного движения отскока или упругой анимации. Когда все строительные блоки готовы, следующий вопрос — как сделать их частью реального рабочего процесса. Написание гибких ключевых кадров — это одно, но обеспечение их надежности в большом проекте требует нескольких стратегий, которые мне пришлось усвоить на собственном горьком опыте. Стратегии реализации и лучшие практики Когда у нас будет солидная библиотека токенов ключевых кадров, настоящая проблема состоит в том, как применить их в повседневной работе.
Соблазн состоит в том, чтобы удалить все ключевые кадры сразу и объявить проблему решенной, но на практике я обнаружил, что наилучшие результаты достигаются при постепенном внедрении. Начните с самых распространенных анимаций, таких как затухание или скольжение. Это легкие победы, которые сразу же приносят пользу и не требуют больших переписываний. Именование – еще один момент, заслуживающий внимания. Согласованный префикс или пространство имен делает очевидным, какие анимации являются токенами, а какие — локальными одноразовыми. Это также предотвращает случайные коллизии и помогает новым членам команды с первого взгляда распознать общую систему. Документация так же важна, как и сам код. Даже короткий комментарий над каждым маркером ключевого кадра может сэкономить часы размышлений позже. Разработчик должен иметь возможность открыть файл токенов, отсканировать необходимый эффект и скопировать шаблон использования прямо в свой компонент. Гибкость — вот что делает этот подход достойным усилий. Предоставляя разумные пользовательские свойства, мы даем командам возможность адаптировать анимацию, не нарушая систему. В то же время постарайтесь не усложнять. Предоставьте те ручки, которые имеют значение, а остальное оставьте при себе. Наконец, помните о доступности. Не каждая анимация нуждается в альтернативе уменьшенного движения, но многим она нужна. Раннее внесение этих корректировок означает, что нам никогда не придется вносить в них изменения позже, и это демонстрирует уровень заботы, который наши пользователи заметят, даже если они никогда не упомянут об этом.
По моему опыту, использование токенов ключевых кадров как части нашего рабочего процесса с токенами дизайна — это то, что делает их популярными. Как только они оказываются на месте, они перестают ощущаться как специальные эффекты и становятся частью языка дизайна, естественным продолжением того, как продукт движется и реагирует. Подведение итогов Анимация может быть одной из самых приятных частей создания интерфейсов, но без структуры она также может стать одним из самых больших источников разочарования. Рассматривая ключевые кадры как токены, вы берете что-то, что обычно беспорядочно и сложно управлять, и превращаете это в четкую и предсказуемую систему. Настоящая ценность заключается не только в экономии нескольких строк кода. Это уверенность в том, что когда вы используете затухание, скольжение, масштабирование или вращение, вы точно знаете, как оно будет вести себя в проекте. Именно в гибкости, возникающей благодаря настраиваемым свойствам без хаоса бесконечных вариаций. И дело в доступности, встроенной в фундамент, а не добавленной какзапоздалая мысль. Я видел, как эти идеи работали в разных командах и разных базах кода, и шаблон всегда один и тот же. Как только токены установлены, ключевые кадры перестают быть разрозненным набором трюков и становятся частью языка дизайна. Они делают продукт более продуманным, более последовательным и более живым. Если вы возьмете что-то из этой статьи, то пусть это будет следующее: анимация заслуживает того же внимания и структуры, которые мы уже уделяем цветам, типографике и интервалам. Небольшие инвестиции в токены ключевых кадров окупаются каждый раз, когда ваш интерфейс перемещается.