- Используйте
clip-pathиmask-imageдля создания собственных геометрических эффектов появления и плавного затухания. - Используйте анимации, управляемые прокруткой (
animation-timeline: scroll()), для второстепенных эффектов, связанных с прокруткой, вместо прослушивателей JS. - Используйте View Transitions, чтобы плавно анимировать переходы между сложными макетами.
Эффективность
- Рекомендуется анимировать
opacityиtransform(включая отдельные свойства преобразования, напримерtranslateвместоleft/right/top/bottom), чтобы анимация оставалась в потоке компоновщика. - Используйте
transition-behavior: allow-discrete,@starting-styleи (для элементов верхнего слоя, таких как<dialog>или[popover])overlay, чтобы анимировать отдельные состояния входа и выхода. Подробнее об анимации входа и выхода элементов и об анимации элементов верхнего слоя…
.popover-reveal {
/* Transition discrete display and top-layer overlay alongside opacity */
transition:
opacity ease-out,
display,
overlay;
transition-duration: 0.2s;
transition-behavior: allow-discrete;
}
Специальные возможности
Используйте медиазапросы prefers-reduced-motion, чтобы отключить интенсивное движение для пользователей, которые этого хотят.
- Добавьте возможность приостановить анимацию. Позвольте пользователям останавливать автоматически запускаемые карусели, баннеры и другие виды анимации.
- Используйте статичные изображения по умолчанию. Подумайте о том, чтобы по умолчанию использовать статичные изображения и позволить пользователям включать анимацию.
- Не превышайте ограничения на мерцание (три раза в секунду). Не используйте быстрое мерцание от светлого к темному. Такие эффекты могут вызвать приступы.
НЕ ПРИМЕНЯЙТЕ animation-duration: 0.01ms; глобально, так как это может сделать некоторые анимации более резкими.
Вместо этого обрабатывайте настройки движения в каждом конкретном случае, используя один из двух подходов, вкладывая запрос @media в правило, чтобы обе версии сохранялись вместе:
- Включите анимацию по умолчанию и уменьшите ее интенсивность с помощью
@media (prefers-reduced-motion: reduce):
/* Good: Dampen spin states or slow down animations for reduced motion */
.spinner {
animation: spin 1s linear infinite;
@media (prefers-reduced-motion: reduce) {
animation: none;
opacity: 0.5;
}
}
progress:not([value]) {
animation: slide 1s infinite linear;
@media (prefers-reduced-motion: reduce) {
animation-duration: 20s;
}
}
- По умолчанию анимация отключена. Чтобы включить ее, используйте метод
@media (prefers-reduced-motion: no-preference):
/* Good: Default to static or gentle states and opt-in to full motion */
.spinner {
opacity: 0.5;
@media (prefers-reduced-motion: no-preference) {
opacity: 1;
animation: spin 1s linear infinite;
}
}
progress:not([value]) {
animation: slide 20s infinite linear;
@media (prefers-reduced-motion: no-preference) {
animation-duration: 1s;
}
}
Как работать с событиями анимации и перехода в JavaScript
В интерфейсах AnimationEvent (animationstart, animationiteration, animationend, animationcancel) и TransitionEvent (transitionrun, transitionstart, transitionend, transitioncancel) event.target возвращает исходный элемент DOM. Чтобы получить доступ к определенному объекту Animation (Animation, CSSAnimation или CSSTransition), который активировал событие, используйте свойство event.animation, доступное только для чтения.
Если event.animation недоступен, обычно можно найти экземпляр Animation, вызвав event.target.getAnimations() и отфильтровав по event.animationName (или event.propertyName для переходов). Однако лучше использовать event.animation напрямую, чтобы избежать ситуаций, когда резервный вариант, фильтрующий event.target.getAnimations(), работает некорректно:
- У анимаций Web Animations API (
element.animate()) нетanimationName, поэтому их нельзя сопоставить по названию при фильтрацииevent.target.getAnimations(). - Фильтрация по
animationNameдляAnimationEventнеоднозначна, когда к одному элементу прикреплено несколько анимаций с одинаковым названием.- Обратите внимание, что фильтрация по
transitionPropertyдляTransitionEventработает, поскольку для каждого свойства перехода существует только одно событие.
- Обратите внимание, что фильтрация по
event.targetвсегда указывает на исходный элемент DOM, поэтому не различает анимации, запущенные на самом элементе и на одном из его псевдоэлементов, тогда какevent.animation.effect.pseudoElementуказывает непосредственно на целевой псевдоэлемент.
// Works in most basic CSS animation cases, but fails for WAAPI animations,
// duplicate animation names on the same element, or pseudo-elements.
document.addEventListener('animationstart', (event) => {
const animation = event.target
.getAnimations()
.find((anim) => anim.animationName === event.animationName);
console.log(animation);
});
// PREFERRED: Directly access the exact Animation object via event.animation
document.addEventListener('animationstart', (event) => {
const animation = event.animation;
console.log(animation);
});
Вы можете определить поддержку функции с помощью 'animation' in AnimationEvent.prototype (или 'animation' in TransitionEvent.prototype).