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

Pubblicata il 27 maggio 2020

Se utilizzate correttamente, le animazioni migliorano la percezione e la memoria degli utenti del tuo brand, guidano le loro azioni e li aiutano a navigare nella tua applicazione, fornendo 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 sia l'animazione CSS che le implementazioni delle transizioni e consentire lo sviluppo di effetti futuri, nonché di scrivere e programmare effetti 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

La creazione di un'animazione utilizzando l'API Web Animations dovrebbe risultare molto familiare se hai utilizzato le regole @keyframe. Innanzitutto, devi creare un oggetto keyframe. Ecco un esempio di questo in CSS:

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

avrà questo aspetto in questo modo in JavaScript:

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

Dove imposti i parametri per l'animazione in CSS:

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

che devi impostare 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 su un elemento, indipendentemente dal fatto che sia stato creato utilizzando element.animate() o utilizzando 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. Quindi, crei due nuove animazioni di opacità, abilitando l'effetto di dissolvenza incrociata. Al termine della transizione, elimina la copia.

Come orchestrare le animazioni con le promesse

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

  • animation.ready ti consente di attendere l'applicazione delle modifiche in attesa (ovvero il passaggio da un metodo di controllo della riproduzione all'altro, ad esempio riproduzione e messa in pausa).
  • animation.finished fornisce un mezzo per eseguire codice JavaScript personalizzato al termine 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 puoi anche applicare effetti a diversi elementi target con opzioni diverse impostate (ad esempio velocità ed easing).

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

Esempio: riprodurre, mettere in pausa e riavvolgere

Cosa può aprire, dovrebbe chiudersi! Fortunatamente, da Chromium 39, l'API Web Animations ci ha fornito la possibilità di riprodurre, mettere in pausa e invertire le nostre 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 del rendimento con le animazioni sostituibili

Quando crei animazioni basate su eventi, ad esempio su 'mousemove', ogni volta viene creata una nuova animazione, che può consumare rapidamente la memoria e peggiorare il rendimento. Per risolvere questo problema, in Chromium 83 sono state introdotte animazioni sostituibili, che consentono la pulizia automatica, in cui le animazioni complete sono contrassegnate come sostituibili e vengono rimosse automaticamente se sostituite da un'altra animazione finita. Considera l'esempio seguente:

Una scia di comete si anima quando il mouse si muove. 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 conteggiando un contatore per 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 allo stile sottostante, nonché tutte le animazioni dell'elemento nell'ordine composito.
  • animation.persist() contrassegna un'animazione come non sostituibile.

Animazioni più fluide con le modalità composte

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 crei animazioni, uno sviluppatore può scrivere brevi effetti distinti e vederli combinati insieme. 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', l'elemento composito aggiunge la rotazione e moltiplica la scala, ottenendo lo stato finale rotate(720deg) scale(1.96). 'accumulate' combina le trasformazioni, generando rotate(720deg) scale(1.8). Per ulteriori informazioni sulle complessità di queste modalità composte, consulta The CompositeOperation e CompositeOperationOrAuto enumerations 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 vengono 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. Dai un'occhiata a queste specifiche per ulteriori approfondimenti sulle novità in arrivo: