Движение — это основная часть любого цифрового опыта, направляющая пользователя от одного взаимодействия к другому. Но есть несколько пробелов в плавной анимации на веб-платформе. К ним относятся возможность легко анимировать анимацию входа и выхода, а также плавную анимацию к верхнему слою и обратно для отклоняемых элементов, таких как диалоговые окна и всплывающие окна.
Чтобы восполнить эти пробелы, Chrome 116 и 117 включают четыре новые функции веб-платформы, которые обеспечивают плавную анимацию и переходы для отдельных свойств.
Эти четыре новые функции включают в себя:
- Возможность анимировать
display
иcontent-visibility
на временной шкале ключевых кадров (из Chrome 116). - Свойство
transition-behavior
с ключевым словомallow-discrete
, позволяющее включать переходы дискретных свойств, таких какdisplay
(из Chrome 117). - Правило
@starting-style
для анимации эффектов входа изdisplay: none
и в верхний слой (из Chrome 117). - Свойство
overlay
для управления поведением верхнего слоя во время анимации (из Chrome 117).
Отображение анимации в ключевых кадрах
Начиная с Chrome 116, вы можете использовать display
и content-visibility
в правилах ключевых кадров. Затем они поменяются местами в момент появления ключевого кадра. Для поддержки этого не требуется никаких дополнительных новых значений:
.card {
animation: fade-out 0.5s forwards;
}
@keyframes fade-out {
100% {
opacity: 0;
display: none;
}
}
В предыдущем примере непрозрачность анимируется до 0 в течение 0,5 с, а затем устанавливается значение «нет». Кроме того, ключевое forwards
гарантирует, что анимация останется в конечном состоянии, так что элемент, к которому она применяется, остается display: none
и opacity: 0
.
Это простой пример, имитирующий то, что можно сделать с переходом (см. демонстрацию в разделе «Переход» ). Однако переходы не позволяют создавать более сложные анимации, как в следующем примере:
.card {
animation: spin-and-delete 1s ease-in forwards;
}
@keyframes spin-and-delete {
0% {
transform: rotateY(0);
filter: hue-rotate(0);
}
80% {
transform: rotateY(360deg);
filter: hue-rotate(180deg);
opacity: 1;
}
100% {
opacity: 0;
display: none;
}
}
Анимация spin-and-delete
— это анимация выхода. Сначала карта будет вращаться вокруг оси Y, проходить через поворот оттенка, а затем на 80%
по временной шкале меняет непрозрачность с 1 на 0. Наконец, карта меняется с display: block
на display: none
.
Для этих анимаций выхода вместо применения их непосредственно к элементу вы можете настроить триггер для анимации. Например, прикрепив прослушиватель событий к кнопке, которая запускает класс для применения анимации, например:
.spin-out {
animation: spin-and-delete 1s ease-in forwards;
}
document.querySelector('.delete-btn').addEventListener('click', () => {
document.querySelector('.card').classList.add('spin-out');
})
В приведенном выше примере теперь есть конечное состояние display:none
. Во многих случаях вам захочется пойти дальше и удалить узел DOM с тайм-аутом, чтобы анимация завершилась первой.
Переход дискретной анимации
В отличие от анимации дискретных свойств с помощью ключевых кадров, для перехода дискретных свойств вам потребуется использовать режим поведения перехода allow-discrete
.
Свойство transition-behavior
Режим allow-discrete
делает возможными дискретные переходы и является значением свойства transition-behavior
. transition-behavior
принимает два значения: normal
и allow-discrete
.
.card {
transition: opacity 0.25s, display 0.25s;
transition-behavior: allow-discrete; /* Note: be sure to write this after the shorthand */
}
.card.fade-out {
opacity: 0;
display: none;
}
Сокращенное обозначение transition
также устанавливает это значение, поэтому вы можете опустить это свойство и вместо этого использовать ключевое словоallow allow-discrete
в конце сокращенного обозначения transition
для каждого перехода.
.card {
transition: opacity 0.5s, display 0.5s allow-discrete;
}
.card.fade-out {
opacity: 0;
display: none;
}
Если вы анимируете несколько дискретных свойств, вам нужно будет включить allow-discrete
после каждого свойства, которое вы хотите анимировать. Например:
.card {
transition: opacity 0.5s, display 0.5s allow-discrete, overlay 0.5s allow-discrete;
}
.card.fade-out {
opacity: 0;
display: none;
}
Правило @starting-style
для анимации входа.
До сих пор в этой статье рассматривались анимации выхода. Для создания анимации входа вам необходимо использовать правило @starting-style
.
Используйте @starting-style
, чтобы применить стиль, который браузер сможет найти до того, как элемент будет открыт на странице. Это состояние «до открытия» (из которого вы выполняете анимацию).
/* 0. IS-OPEN STATE */
/* The state at which the element is open + transition logic */
.item {
height: 3rem;
display: grid;
overflow: hidden;
transition: opacity 0.5s, transform 0.5s, height 0.5s, display 0.5s allow-discrete;
}
/* 1. BEFORE-OPEN STATE */
/* Starting point for the transition */
@starting-style {
.item {
opacity: 0;
height: 0;
}
}
/* 2. EXITING STATE */
/* While it is deleting, before DOM removal in JS, apply this
transformation for height, opacity, and a transform which
skews the element and moves it to the left before setting
it to display: none */
.is-deleting {
opacity: 0;
height: 0;
display: none;
transform: skewX(50deg) translateX(-25vw);
}
Теперь у вас есть состояние входа и выхода для этих элементов списка TODO:
Анимация элементов в верхнем слое и обратно
Чтобы анимировать элементы в верхнем слое и обратно, укажите @starting-style
в «открытом» состоянии, чтобы сообщить браузеру, откуда начинать анимацию. Открытое состояние диалога определяется атрибутом [open]
. Для поповера используйте псевдокласс :popover-open
.
Простой пример диалога может выглядеть так:
/* 0. IS-OPEN STATE */
dialog[open] {
translate: 0 0;
}
/* 1. BEFORE-OPEN STATE */
@starting-style {
dialog[open] {
translate: 0 100vh;
}
}
/* 2. EXIT STATE */
dialog {
transition: translate 0.7s ease-out, overlay 0.7s ease-out allow-discrete, display 0.7s ease-out allow-discrete;
translate: 0 100vh;
}
В следующем примере эффекты входа и выхода различны. Войдите, анимируя вверх из нижней части области просмотра, выйдите из эффекта в верхнюю часть области просмотра. Он также написан с использованием вложенного CSS для большей визуальной инкапсуляции.
При анимации всплывающего окна используйте псевдокласс :popover-open
вместо использованного ранее атрибута open
.
.settings-popover {
&:popover-open {
/* 0. IS-OPEN STATE */
/* state when popover is open, BOTH:
what we're transitioning *in* to
and transitioning *out* from */
transform: translateY(0);
opacity: 1;
/* 1. BEFORE-OPEN STATE */
/* Initial state for what we're animating *in* from,
in this case: goes from lower (y + 20px) to center */
@starting-style {
transform: translateY(20px);
opacity: 0;
}
}
/* 2. EXIT STATE */
/* Initial state for what we're animating *out* to ,
in this case: goes from center to (y - 50px) higher */
transform: translateY(-50px);
opacity: 0;
/* Enumerate transitioning properties,
including display and allow-discrete mode */
transition: transform 0.5s, opacity 0.5s, display 0.5s allow-discrete;
}
свойство overlay
Наконец, чтобы затемнить popover
или dialog
на верхнем слое, добавьте свойство overlay
в список переходов. popover
и dialog
окна экранируют клипы-предки и преобразуют их, а также помещают содержимое в верхний слой. Если вы не overlay
переход, ваш элемент немедленно снова станет обрезанным, трансформированным и закрытым, и вы не увидите, как произойдет переход.
[open] {
transition: opacity 1s, display 1s allow-discrete;
}
Вместо этого включите overlay
в переход или анимацию, чтобы анимировать overlay
вместе с остальными функциями и убедитесь, что оно остается в верхнем слое при анимации. Это будет выглядеть намного более гладко.
[open] {
transition: opacity 1s, display 1s allow-discrete, overlay 1s allow-discrete;
}
Кроме того, если в верхнем слое открыто несколько элементов, наложение помогает контролировать плавный переход в верхний слой и из него. Вы можете увидеть разницу на этом простом примере . Если вы не применяете overlay
ко второму поповеру при его удалении, он сначала выйдет из верхнего слоя, перепрыгнув за другой поповер, прежде чем начать переход. Это не очень плавный эффект.
Примечание о переходах между видами
Если вы вносите изменения в DOM, например добавляете и удаляете элементы из DOM, еще одним отличным решением для плавной анимации являются переходы между представлениями . Вот два из приведенных выше примеров, построенных с использованием переходов представлений.
В этой первой демонстрации вместо настройки @starting-style
и других преобразований CSS переходы будут обрабатываться переходами представлений. Переход вида настраивается следующим образом:
Во-первых, в CSS присвойте каждой карточке индивидуальное view-transition-name
.
.card-1 {
view-transition-name: card-1;
}
.card-2 {
view-transition-name: card-2;
}
/* etc. */
Затем в JavaScript оберните мутацию DOM (в данном случае удаление карты) в переход представления.
deleteBtn.addEventListener('click', () => {
// Check for browser support
if (document.startViewTransition) {
document.startViewTransition(() => {
// DOM mutation
card.remove();
});
}
// Alternative if no browser support
else {
card.remove();
}
})
Теперь браузер может обрабатывать затухание и преобразование каждой карты в новое положение.
Еще один пример того, где это может быть удобно, — демонстрация добавления/удаления элементов списка. В этом случае вам нужно будет не забыть добавить уникальное view-transition-name
для каждой созданной карты.
Заключение
Эти новые функции платформы приближают нас на один шаг к плавной анимации входа и выхода на веб-платформе. Чтобы узнать больше, перейдите по этим ссылкам: