Miglioramenti all'API Web Animations in Chromium 84

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

Kevin Ellis
Kevin Ellis

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 nella tua applicazione, fornendo contesto in uno spazio digitale.

L'API Web Animations è uno strumento che consente agli sviluppatori di scrivere animazioni imperative con JavaScript. È stata scritta per supportare le implementazioni delle animazioni e delle transizioni CSS e per consentire lo sviluppo di effetti futuri e la possibilità di comporre e sincronizzare gli effetti esistenti.

Mentre Firefox e Safari hanno già implementato il set completo di funzionalità specifiche, Chromium 84 introduce una serie di funzionalità precedentemente non supportate su Chrome ed Edge, consentendo l'interoperabilità tra browser.

L'API Web Animations ha raggiunto per la prima volta Chromium nella versione 36, luglio 2014. Ora le specifiche saranno complete, nella versione 84, a partire da luglio 2020.
La lunga cronologia dell'API Web Animations in Chromium.

Per iniziare

La creazione di un'animazione tramite l'API Web Animations dovrebbe essere familiare se hai usato le regole @keyframe. Innanzitutto, devi creare un oggetto fotogramma chiave. Potresti avere un aspetto simile a questo in CSS:

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

avrà il seguente aspetto 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;
}

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 è quasi la stessa, ma con JavaScript ottieni un paio di superpoteri che non hai solo con CSS. Ciò include la possibilità di applicare effetti in sequenza e un maggiore controllo degli stati di riproduzione.

Oltre element.animate()

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

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

Innanzitutto "get" i fotogrammi chiave della transizione per determinare da dove stiamo passando. Quindi, creerai due nuove animazioni di opacità per attivare l'effetto dissolvenza incrociata. Al termine della dissolvenza incrociata, elimini la copia.

Orchestrare animazioni con 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 che le modifiche in attesa abbiano effetto (ossia passando da un metodo di controllo di riproduzione all'altro, ad esempio riproduzione e pausa).
  • animation.finished consente di eseguire codice JavaScript personalizzato al termine di un'animazione.

Continuiamo con l'esempio e creiamo una catena di animazione orchestrata con animation.finished. In questo caso, abbiamo una trasformazione verticale (scaleY), seguita da una trasformazione orizzontale (scaleX), seguita da una modifica di opacità su 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 concatenato queste animazioni utilizzando animation.finished.then() prima di eseguire il successivo set di animazioni nella catena. In questo modo le animazioni vengono visualizzate in ordine e puoi persino applicare effetti a diversi elementi target con opzioni diverse impostate (come velocità e facilità).

All'interno di CSS, questo sarebbe difficile da ricreare, soprattutto in caso di applicazione di animazioni uniche, ma in sequenza a più elementi. Prima di attivare le animazioni nella sequenza, dovresti utilizzare un @keyframe, stabilire le percentuali di temporizzazione corrette per posizionare le animazioni e utilizzare animation-delay.

Esempio: riprodurre, mettere in pausa e invertire

Cosa può aprire, dovrebbe chiudersi! Fortunatamente, a partire da Chromium 39, l'API Web Animations ci ha fornito la possibilità di riprodurre, mettere in pausa e invertire le animazioni.

Puoi scattare l'animazione qui sopra e ottenere un'animazione fluida e invertita quando fai di nuovo clic sul pulsante usando .reverse(). In questo modo, puoi creare un'interazione più fluida e contestuale per la nostra finestra modale.

Esempio di apertura e chiusura modale al clic su un pulsante. Guarda la demo su Glitch

Puoi creare due animazioni in attesa di riproduzione (openModal e una trasformazione di opacità in linea), quindi mettere in pausa una delle animazioni, ritardandola fino alla fine dell'altra. Puoi quindi utilizzare le promesse di attendere la fine di ognuna prima di giocare. Infine, puoi verificare 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 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 la posizione iniziale non è specificata. Questo è un esempio di utilizzo di foto chiave parziali. Il gestore del mouse esegue alcune operazioni qui: imposta una nuova posizione di fine e attiva una nuova animazione. La nuova posizione iniziale viene dedotta dalla posizione sottostante attuale.

È possibile attivare nuove transizioni 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, che può consumare rapidamente memoria e compromettere le prestazioni. Per risolvere questo problema, in Chromium 83 sono state introdotte animazioni sostituibili, che consentono la pulizia automatica, in cui le animazioni terminate sono contrassegnate come sostituibili e rimosse automaticamente se sostituite da un'altra animazione terminata. Considera l'esempio seguente:

Una scia di cometa 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 muove, il browser ricalcola la posizione di ciascuna pallina nel sentiero cometa e crea un'animazione per questo nuovo punto. Il browser ora sa di dover rimuovere le vecchie animazioni (consentendo la sostituzione) quando:

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

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

Esistono alcuni metodi aggiuntivi per ottimizzare ulteriormente il controllo delle animazioni:

  • animation.replaceState() consente di monitorare se un'animazione è attiva, persistente o rimossa.
  • animation.commitStyles() aggiorna lo stile di un elemento in base allo stile sottostante, insieme a tutte le animazioni dell'elemento nell'ordine composito.
  • animation.persist() contrassegna un'animazione come non sostituibile.

Animazioni più fluide con le modalità composita

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 di "sostituzione". Le modalità composite consentono agli sviluppatori di scrivere animazioni distinte e di avere il controllo su come vengono combinati gli effetti. Ora sono supportate tre modalità composite: 'replace' (la modalità predefinita), 'add' e 'accumulate'.

Quando crei animazioni composte, uno sviluppatore può scrivere brevi effetti distinti e vederli combinati insieme. Nell'esempio che segue, applichiamo una rotazione e un fotogramma chiave in scala a ogni casella. L'unica regolazione è la modalità composita, aggiunta come opzione:

Una demo che mostra le modalità composite predefinite, aggiuntive e cumulative. Guarda la demo su Glitch

Nella modalità composita 'replace' predefinita, l'animazione finale sostituisce la proprietà di trasformazione e termina a rotate(360deg) scale(1.4). Per 'add', l'elemento composito somma la rotazione e moltiplica la scala, ottenendo lo stato finale di 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 and CompositeOperationOrAuto enumerations dalla specifica Web Animations.

Diamo un'occhiata a un esempio di elemento UI:

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

In questo caso, 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 dalla parte superiore della pagina, mentre la seconda, una micro-animazione, applica un leggero 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' });
  });

Passaggi successivi dell'API Web Animations

Queste sono tutte aggiunte interessanti alle funzionalità di animazione nei browser odierni e altre novità sono in arrivo. Consulta queste specifiche future per ulteriori approfondimenti sulle novità in arrivo: