- Use
clip-pathemask-imagepara revelações geométricas personalizadas e esmaecimentos suaves. - Use Animações orientadas por rolagem (
animation-timeline: scroll()) para efeitos de rolagem não essenciais em vez de listeners JS. - Use as transições de visualização para animar entre estados de layout complexos de forma integrada.
Desempenho
- Dê preferência à animação de
opacityetransform(incluindo propriedades de transformação individuais, comotranslateem vez deleft/right/top/bottom) para garantir que as animações permaneçam na linha de execução do compositor. - Use
transition-behavior: allow-discrete,@starting-stylee (para elementos de camada superior, como<dialog>ou[popover])overlaypara animar estados de entrada e saída discretos de forma nativa. Consulte Animar a entrada e saída de elementos e Animar elementos de e para a camada superior.
.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;
}
Acessibilidade
Use consultas de mídia prefers-reduced-motion para desativar movimentos intensos para os usuários que preferem isso.
- Ofereça um mecanismo de pausa: permita que os usuários interrompam carrosséis, banners ou outras animações persistentes de execução automática.
- Use visualizações estáticas como padrão: considere usar estados estáticos como padrão e permitir que os usuários ativem o movimento.
- Não exceda os limites de flash (três por segundo): nunca inclua flashes rápidos de luz para escuro. Esses efeitos podem causar convulsões.
NÃO aplique animation-duration: 0.01ms; globalmente, porque isso pode fazer com que algumas animações fiquem mais bruscas.
Em vez disso, processe as preferências de movimento caso a caso usando uma das duas abordagens, aninhando a consulta @media dentro da regra para que as duas versões sejam mantidas juntas:
- Comece com as animações ativadas por padrão e reduza-as usando
@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;
}
}
- Comece sem animações por padrão e ative-as usando
@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;
}
}
Como trabalhar com eventos de animação e transição em JavaScript
Nas interfaces AnimationEvent (animationstart, animationiteration, animationend, animationcancel) e TransitionEvent (transitionrun, transitionstart, transitionend, transitioncancel), event.target fornece o elemento DOM de origem. Para acessar o objeto Animation específico (Animation, CSSAnimation ou CSSTransition) que acionou o evento, use a propriedade somente leitura event.animation.
Quando event.animation não estiver disponível, geralmente é possível encontrar a instância Animation chamando event.target.getAnimations() e filtrando por event.animationName (ou event.propertyName para transições). No entanto, é preferível usar event.animation diretamente para evitar vários cenários em que esse substituto que filtra event.target.getAnimations() não funciona como esperado:
- As animações da API Web Animations (
element.animate()) não têm umanimationName, então não podem ser correspondidas por nome ao filtrarevent.target.getAnimations(). - Filtrar por
animationNameparaAnimationEvents é ambíguo quando várias animações com o mesmo nome são anexadas ao mesmo elemento.- A filtragem em
transitionPropertyparaTransitionEvents funciona porque há apenas um evento por propriedade de transição.
- A filtragem em
event.targetsempre aponta para o elemento DOM de origem, portanto, não distingue entre animações em execução no próprio elemento e em um dos pseudoelementos, enquantoevent.animation.effect.pseudoElementexpõe o pseudoelemento de destino diretamente.
// 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);
});
É possível detectar o suporte a recursos usando 'animation' in AnimationEvent.prototype (ou 'animation' in TransitionEvent.prototype).