- Utilizza
clip-pathemask-imageper rivelazioni geometriche personalizzate e dissolvenze fluide. - Utilizza le animazioni basate sullo scorrimento (
animation-timeline: scroll()) per gli effetti di scorrimento non essenziali anziché i listener JS. - Utilizza le transizioni di visualizzazione per animare senza problemi gli stati di layout complessi.
Prestazioni
- Preferisci animare
opacityetransform(incluse le singole proprietà di trasformazione, ad esempiotranslateanzichéleft/right/top/bottom) per assicurarti che le animazioni rimangano nel thread del compositore. - Utilizza
transition-behavior: allow-discrete,@starting-stylee (per gli elementi di livello superiore come<dialog>o[popover])overlayper animare in modo nativo gli stati di entrata e uscita discreti; consulta Animare l'entrata e l'uscita degli elementi e Animare gli elementi da e verso il livello superiore.
.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;
}
Accessibilità
Utilizza le query supporti prefers-reduced-motion per disattivare i movimenti intensi per gli utenti che lo preferiscono.
- Fornisci un meccanismo di pausa: consenti agli utenti di interrompere la riproduzione automatica di caroselli, banner o altre animazioni persistenti.
- Imposta come predefinite le visualizzazioni statiche: valuta la possibilità di impostare come predefiniti gli stati statici e di consentire agli utenti di attivare il movimento.
- Non superare i limiti di lampeggiamento (tre al secondo): non includere mai un lampeggiamento rapido da chiaro a scuro. Questi effetti possono causare convulsioni.
NON applicare animation-duration: 0.01ms; a livello globale, in quanto alcune animazioni potrebbero diventare più stridenti.
Gestisci invece le preferenze di movimento caso per caso utilizzando uno dei due approcci, nidificando la query @media all'interno della regola in modo che entrambe le versioni vengano mantenute insieme:
- Inizia con le animazioni attivate per impostazione predefinita e riducile utilizzando
@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;
}
}
- Inizia senza animazioni per impostazione predefinita e attivale utilizzando
@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;
}
}
Utilizzo degli eventi di animazione e transizione in JavaScript
Sia nell'interfaccia AnimationEvent (animationstart, animationiteration, animationend, animationcancel) che nell'interfaccia TransitionEvent (transitionrun, transitionstart, transitionend, transitioncancel), event.target fornisce l'elemento DOM di origine. Per accedere all'oggetto Animation specifico (Animation, CSSAnimation o CSSTransition) che ha attivato l'evento, utilizza la proprietà di sola lettura event.animation.
Quando event.animation non è disponibile, in genere puoi trovare l'istanza Animation chiamando event.target.getAnimations() e filtrando per event.animationName (o event.propertyName per le transizioni). Tuttavia, è preferibile utilizzare direttamente event.animation per evitare diversi scenari in cui questo fallback che filtra event.target.getAnimations() non funziona come previsto:
- Le animazioni dell'API Web Animations (
element.animate()) non hanno unanimationName, quindi non possono essere abbinate per nome quando si filtraevent.target.getAnimations(). - Il filtro per
animationNameperAnimationEventè ambiguo quando più animazioni con lo stesso nome sono associate allo stesso elemento.- Tieni presente che il filtro su
transitionPropertyperTransitionEventfunziona perché esiste un solo evento per proprietà di transizione.
- Tieni presente che il filtro su
event.targetpunta sempre all'elemento DOM di origine, quindi non distingue tra le animazioni in esecuzione sull'elemento stesso e quelle su uno dei suoi pseudo-elementi, mentreevent.animation.effect.pseudoElementespone direttamente lo pseudo-elemento di destinazione.
// 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);
});
Puoi rilevare il supporto delle funzionalità utilizzando 'animation' in AnimationEvent.prototype (o 'animation' in TransitionEvent.prototype).