Miglioramenti all'API Web Animations in Chromium 84

Orchestrazione delle animazioni con le promesse, miglioramenti delle prestazioni con animazioni sostituibili, animazioni più fluide con le modalità composite e altro ancora.

Kevin Ellis
Kevin Ellis

Data di pubblicazione: 27 maggio 2020

Se utilizzate correttamente, le animazioni migliorano la percezione e la memoria degli utenti del tuo brand, guidano le azioni degli utenti e aiutano gli utenti a navigare nell'applicazione, fornendo loro il contesto in uno spazio digitale.

L'API Web Animations è uno strumento che consente agli sviluppatori di scrivere animazioni imperative con JavaScript. È stato scritto per supportare le implementazioni di animazioni e transizioni CSS e consentire lo sviluppo di effetti futuri, nonché la composizione e la temporizzazione di quelli esistenti.

Sebbene Firefox e Safari abbiano già implementato l'intero insieme di funzionalità delle specifiche, Chromium 84 offre una serie di funzionalità non supportate in precedenza a Chrome ed Edge, consentendo l'interoperabilità tra browser.

L'API Web Animations è stata introdotta per la prima volta in Chromium nella versione 36, a luglio 2014. Ora la specifica sarà completata nella versione 84, che verrà lanciata a luglio 2020.
La lunga storia dell'API Web Animations in Chromium.

Per iniziare

Se hai utilizzato le regole @keyframe, dovresti creare un'animazione utilizzando l'API Web Animations. Innanzitutto, devi creare un oggetto keyframe. In CSS potrebbe avere il seguente aspetto :

@keyframes openAnimation {
  0% {
    transform: scale(0);
  }
  100% {
    transform: scale(1);
  }
}

in JavaScript avrà il seguente aspetto:

const openAnimation = [
  { transform: 'scale(0)' },
  { transform: 'scale(1)' },
];

Dove imposti i parametri per l'animazione in CSS:

.modal {
  animation: openAnimation 1s 1 ease-in;
}

in JS:

document.querySelector('.modal').animate(
    openAnimation, {
      duration: 1000, // 1s
      iterations: 1, // single iteration
      easing: 'ease-in' // easing function
    }
);

La quantità di codice è più o meno la stessa, ma con JavaScript hai a disposizione un paio di superpoteri che non hai con il solo CSS. Sono incluse la possibilità di mettere in sequenza gli effetti e un maggiore controllo sugli stati di riproduzione.

Oltre element.animate()

Tuttavia, con l'aggiornamento, l'API Web Animations non è più limitata alle animazioni create utilizzando element.animate(). Possiamo anche manipolare le animazioni e le transizioni CSS.

getAnimations() è un metodo che restituisce tutte le animazioni di un elemento, indipendentemente dal fatto che sia stato creato utilizzando element.animate() o le regole CSS (animazione o transizione CSS). Ecco un esempio di come funziona:

Per prima cosa "get" i fotogrammi chiave per la transizione per determinare da dove avviene la transizione. Poi, crea due nuove animazioni di opacità, attivando l'effetto di transizione in dissolvenza. Una volta completata la dissolvenza incrociata, elimini la copia.

Come orchestrare le animazioni con le promesse

In Chromium 84 ora hai due metodi che possono essere utilizzati con le promesse: animation.ready e animation.finished.

  • animation.ready ti consente di attendere che le modifiche in attesa diventino effettive (ovvero passando da un metodo di controllo della riproduzione come quello di riproduzione e pausa)
  • animation.finished fornisce un mezzo per eseguire il codice JavaScript personalizzato al completamento di un'animazione.

Proseguendo con l'esempio, creiamo una catena di animazioni orchestrata con animation.finished. In questo caso, viene eseguita una trasformazione verticale (scaleY), seguita da una trasformazione orizzontale (scaleX), seguita da una modifica dell'opacità in un elemento secondario:

Applicazione di trasformazioni e opacità a un elemento modale di apertura. Guarda la demo su Codepen
const transformAnimation = modal.animate(openModal, openModalSettings);
transformAnimation.finished.then(() => { text.animate(fadeIn, fadeInSettings)});

Abbiamo collegato queste animazioni utilizzando animation.finished.then() prima di eseguire il set di animazione successivo nella catena. In questo modo, le animazioni vengono visualizzate in ordine e applichi effetti a diversi elementi target con diverse opzioni impostate (come velocità e semplicità).

In CSS, sarebbe complicato ricrearlo, soprattutto quando si applicano animazioni uniche, ma sequenziate, a più elementi. Devi utilizzare @keyframe, ordinare le percentuali di temporizzazione corrette per posizionare le animazioni e usare animation-delay prima di attivare le animazioni nella sequenza.

Esempio: riproduci, metti in pausa e inverti la riproduzione

Ciò che può essere aperto, deve essere chiuso. Fortunatamente, a partire da Chromium 39, l'API Web Animations ci ha permesso di riprodurre, mettere in pausa e invertire le animazioni.

Puoi prendere l'animazione mostrata in precedenza e applicarle un'animazione fluida e inversa facendo di nuovo clic sul pulsante utilizzando .reverse(). In questo modo, puoi creare un'interazione più fluida e contestuale per la nostra finestra modale.

Un esempio di apertura e chiusura di una finestra modale al clic del pulsante. Guarda la demo su Glitch

Puoi creare due animazioni in attesa di riproduzione (openModal e una trasformazione di opacità in linea) e mettere in pausa una delle animazioni, ritardandola fino al termine dell'altra. Puoi quindi utilizzare le promesse per attendere il completamento di ciascuna prima di iniziare a giocare. Infine, puoi controllare se è impostato un flag e invertire ogni animazione.

Esempio: interazioni dinamiche con fotogrammi chiave parziali

Esempio di retargeting, in cui un clic del mouse regola l'animazione in base a una nuova posizione. Guarda la demo su Glitch
selector.animate([{transform: `translate(${x}px, ${y}px)`}],
    {duration: 1000, fill: 'forwards'});

In questo esempio è presente un solo fotogramma chiave e nessuna posizione di inizio specificata. Questo è un esempio di utilizzo dei keyframe parziali. Il gestore del mouse esegue alcune operazioni: imposta una nuova posizione di fine e attiva una nuova animazione. La nuova posizione iniziale viene dedotta dalla posizione di base corrente.

Le nuove transizioni possono essere attivate mentre quelle esistenti sono ancora in esecuzione. Ciò significa che la transizione corrente viene interrotta e ne viene creata una nuova.

Miglioramenti delle prestazioni con animazioni sostituibili

Quando crei animazioni basate su eventi, ad esempio 'mousemove', viene creata ogni volta una nuova animazione, con un rapido consumo di memoria e un peggioramento delle prestazioni. Per risolvere questo problema, in Chromium 83 sono state introdotte le animazioni sostituibili, che consentono la pulizia automatica, in cui le animazioni complete vengono contrassegnate come sostituibili e rimosse automaticamente se sostituite da un'altra animazione completa. Considera l'esempio seguente:

Una scia cometa si anima quando il mouse si sposta. Guarda la demo su Glitch
elem.addEventListener('mousemove', evt => {
  rectangle.animate(
    { transform: translate(${evt.clientX}px, ${evt.clientY}px) },
    { duration: 500, fill: 'forwards' }
  );
});

Ogni volta che il mouse si sposta, il browser ricalcola la posizione di ogni sfera nel percorso della cometa e crea un'animazione in questo nuovo punto. Ora il browser sa di rimuovere le vecchie animazioni (attivando la sostituzione) quando:

  1. L'animazione è terminata.
  2. Esistono una o più animazioni più in alto nell'ordine composito che sono state completate.
  3. Le nuove animazioni animano le stesse proprietà.

Puoi vedere esattamente quante animazioni vengono sostituite eseguendo il conteggio di un contatore con ogni animazione rimossa, utilizzando anim.onremove per attivare il contatore.

Esistono alcuni metodi aggiuntivi per migliorare ulteriormente il controllo dell'animazione:

  • animation.replaceState() fornisce un mezzo per monitorare se un'animazione è attiva, persistente o rimossa.
  • animation.commitStyles() aggiorna lo stile di un elemento in base a quello sottostante, oltre a tutte le animazioni dell'elemento nell'ordine composto.
  • animation.persist() contrassegna un'animazione come non sostituibile.

Animazioni più fluide con le modalità composite

Con l'API Web Animations, ora puoi impostare la modalità composita delle animazioni, il che significa che possono essere additive o cumulative, oltre alla modalità predefinita "sostituzione". Le modalità composite consentono agli sviluppatori di scrivere animazioni distinte e di avere il controllo sulla combinazione degli effetti. Ora sono supportate tre modalità composite: 'replace' (la modalità predefinita), 'add' e 'accumulate'.

Quando componi le animazioni, uno sviluppatore può scrivere effetti brevi e distinti e visualizzarli combinati. Nell'esempio seguente, a ogni riquadro viene applicata una keyframe di rotazione e scala, con l'unico aggiustamento della modalità composita, aggiunta come opzione:

Una demo che mostra le modalità composite predefinite, di somma e di cumulo. Guarda la demo su Glitch

Nella modalità composita 'replace' predefinita, l'animazione finale sostituisce la proprietà transform e termina a rotate(360deg) scale(1.4). Per 'add', la composizione aggiunge la rotazione e moltiplica la scala, ottenendo uno stato finale di rotate(720deg) scale(1.96). 'accumulate' combina le trasformazioni, ottenendo rotate(720deg) scale(1.8). Per saperne di più sulle complessità di queste modalità composite, consulta le enumerazioni CompositeOperation e CompositeOperationOrAuto delle specifiche delle animazioni web.

Dai un'occhiata al seguente esempio di elemento dell'interfaccia utente:

Un menu a discesa elastico a cui sono applicate due animazioni composite. Guarda la demo su Glitch

Qui sono composte due animazioni top. La prima è una macro-animazione, che sposta il menu a discesa per l'intera altezza del menu stesso come effetto di scorrimento dall'alto della pagina, mentre la seconda, una micro-animazione, applica un piccolo rimbalzo quando raggiunge il fondo. L'utilizzo della modalità composita 'add' consente una transizione più fluida.

const dropDown = menu.animate(
    [
      { top: `${-menuHeight}px`, easing: 'ease-in' },
      { top: 0 }
    ], { duration: 300, fill: 'forwards' });

  dropDown.finished.then(() => {
    const bounce = menu.animate(
      [
        { top: '0px', easing: 'ease-in' },
        { top: '10px', easing: 'ease-out' },
        { ... }
      ], { duration: 300, composite: 'add' });
  });

Novità per l'API Web Animations

Si tratta di interessanti aggiunte alle funzionalità di animazione dei browser attuali e sono previste altre aggiunte in futuro. Consulta queste specifiche future per saperne di più sulle prossime novità: