Quattro nuove funzionalità CSS per animazioni di ingresso e uscita fluide

Una Kravets
Una Kravets
Joey Arhar
Joey Arhar

Il movimento è una parte fondamentale di qualsiasi esperienza digitale e guida l'utente da un'interazione all'altra. Ci sono però alcune lacune nelle animazioni fluide della piattaforma web. Queste includono la possibilità di animare facilmente le animazioni di entrata e uscita, nonché di animare in modo fluido da e verso il livello superiore per gli elementi ignorabili come finestre di dialogo e popover.

Per colmare queste lacune, Chrome 116 e Chrome 117 includono quattro nuove funzionalità delle piattaforme web, che consentono animazioni e transizioni fluide per proprietà discrete.

Queste quattro nuove funzionalità includono:

  • La possibilità di animare display e content-visibility in una sequenza temporale di un fotogramma chiave (da Chrome 116).
  • La proprietà transition-behavior con la parola chiave allow-discrete per consentire le transizioni di proprietà discrete come display (da Chrome 117).
  • La regola @starting-style per animare gli effetti delle voci da display: none e nel livello superiore (Da Chrome 117).
  • La proprietà overlay per controllare il comportamento del livello superiore durante un'animazione (da Chrome 117). ## Mostrare animazioni nei fotogrammi chiave

A partire da Chrome 116, puoi utilizzare display e content-visibility nelle regole per i fotogrammi chiave. Questi verranno scambiati nel momento in cui si verifica il fotogramma chiave. Non sono richiesti nuovi valori aggiuntivi a supporto di ciò:

.card {
  animation: fade-out 0.5s forwards;
}

@keyframes fade-out {
  100% {
    opacity: 0;
    display: none;
  }
}

L'esempio precedente imposta l'opacità su 0 nel periodo di 0,5 secondi, quindi imposta la visualizzazione su nessuno. Inoltre, la parola chiave forwards assicura che l'animazione rimanga nello stato finale, in modo che l'elemento a cui viene applicata rimanga display: none e opacity: 0.

Questo è un semplice esempio che imita ciò che puoi fare con una transizione (vedi la demo nella sezione sulla transizione). Tuttavia, le transizioni non consentono di creare animazioni più complesse, come nell'esempio seguente:

.card {
  animation: spin-and-delete 1s ease-in forwards;
}

@keyframes spin-and-delete {
  0% {
    transform: rotateY(0);
    filter: hue-rotate(0);
  }
  80% {
    transform: rotateY(360deg);
    filter: hue-rotate(180deg);
    opacity: 1;
  }
  100% {
    opacity: 0;
    display: none;
  }
}

L'animazione spin-and-delete è un'animazione di uscita. In primo luogo, la scheda ruoterà sull'asse y, si sposterà in una rotazione delle tonalità, quindi, nella sequenza temporale 80%, passerà la sua opacità da 1 a 0. Infine, la carta passa da display: block a display: none.

Per queste animazioni di uscita, invece di applicarle direttamente a un elemento, puoi impostare un attivatore per le animazioni. Ad esempio, associando un listener di eventi a un pulsante che attiva una classe per applicare l'animazione, come nell'esempio seguente:

.spin-out {
   animation: spin-and-delete 1s ease-in forwards;
}
document.querySelector('.delete-btn').addEventListener('click', () => {
 document.querySelector('.card').classList.add('spin-out');
})

Lo stato finale dell'esempio riportato sopra ora è display:none. In molti casi è consigliabile spingersi oltre e rimuovere il nodo DOM con un timeout per consentire il primo completamento dell'animazione.

Transizione da animazioni discrete

A differenza dell'animazione delle proprietà discrete con i fotogrammi chiave, per trasferire le proprietà discrete devi utilizzare la modalità di transizione allow-discrete.

La proprietà transition-behavior

Ciò che rende possibili le transizioni discrete è la modalità allow-discrete, un valore della proprietà transition-behavior. transition-behavior accetta due valori: normal e allow-discrete.

.card {
  transition: opacity 0.25s, display 0.25s;
  transition-behavior: allow-discrete; /* Note: be sure to write this after the shorthand */
}

.card.fade-out {
  opacity: 0;
  display: none;
}
Nota: questa demo di transizione mostra una tecnica diversa rispetto alla prima demo di animazione, ma visivamente simile.

Anche l'abbreviazione transition imposta questo valore, quindi puoi omettere la proprietà e utilizzare invece la parola chiave allow-discrete alla fine dell'abbreviazione transition per ogni transizione.

.card {
  transition: opacity 0.5s, display 0.5s allow-discrete;
}

.card.fade-out {
  opacity: 0;
  display: none;
}

Se vuoi animare più proprietà discrete, devi includere allow-discrete dopo ogni proprietà che vuoi animare. Ad esempio:

.card {
  transition: opacity 0.5s, display 0.5s allow-discrete, overlay 0.5s allow-discrete;
}

.card.fade-out {
  opacity: 0;
  display: none;
}

La regola @starting-style per le animazioni delle voci

Finora in questo articolo sono state illustrate le animazioni di uscita. Per creare animazioni di entrata devi utilizzare la regola @starting-style.

Utilizza @starting-style per applicare uno stile che il browser può cercare prima che l'elemento sia aperto nella pagina. Si tratta dello stato "prima dell'apertura" (dal punto in cui viene eseguita l'animazione).

/*  0. BEFORE-OPEN STATE   */
/*  Starting point for the transition */
@starting-style {
  .item {
    opacity: 0;
    height: 0;
  }
}

/*  1. IS-OPEN STATE   */
/*  The state at which the element is open + transition logic */
.item {
  height: 3rem;
  display: grid;
  overflow: hidden;
  transition: opacity 0.5s, transform 0.5s, height 0.5s, display 0.5s allow-discrete;
}

/*  2. EXITING STATE   */
/*  While it is deleting, before DOM removal in JS, apply this
    transformation for height, opacity, and a transform which
    skews the element and moves it to the left before setting
    it to display: none */
.is-deleting {
  opacity: 0;
  height: 0;
  display: none;
  transform: skewX(50deg) translateX(-25vw);
}

Ora hai sia uno stato di entrata che di uscita per questi elementi dell'elenco DA FARE:

Animazione degli elementi da e verso il livello superiore

Per animare gli elementi da e verso il livello superiore, specifica @starting-style nello stato "aperto" per indicare al browser da dove eseguire l'animazione. Per una finestra di dialogo, lo stato aperto viene definito con l'attributo [open]. Per un popover, utilizza la pseudoclasse :popover-open.

Ecco un semplice esempio di una finestra di dialogo:

/*   0. BEFORE-OPEN STATE   */
@starting-style {
  dialog[open] {
    translate: 0 100vh;
  }
}

/*   1. IS-OPEN STATE   */
dialog[open] {
  translate: 0 0;
}

/*   2. EXIT STATE   */
dialog {
  transition: translate 0.7s ease-out, overlay 0.7s ease-out allow-discrete, display 0.7s ease-out allow-discrete;
  translate: 0 100vh;
}

Nel prossimo esempio, gli effetti di entrata e di uscita sono diversi. Inizia animando verso l'alto dalla parte inferiore dell'area visibile, quindi esci dall'effetto nella parte superiore dell'area visibile. Inoltre, è scritto con CSS nidificato per un maggiore incapsulamento visivo.

Quando crei un popover, utilizza la pseudoclasse :popover-open anziché l'attributo open usato in precedenza.

.settings-popover {
  &:popover-open {
    /*  0. BEFORE-OPEN STATE  */
    /*  Initial state for what we're animating *in* from, 
        in this case: goes from lower (y + 20px) to center  */
    @starting-style {
      transform: translateY(20px);
      opacity: 0;
    }
    
    /*  1. IS-OPEN STATE  */
    /*  state when popover is open, BOTH:
        what we're transitioning *in* to 
        and transitioning *out* from */
    transform: translateY(0);
    opacity: 1;
  }
  
  /*  2. EXIT STATE  */
  /*  Initial state for what we're animating *out* to , 
      in this case: goes from center to (y - 50px) higher */
  transform: translateY(-50px);
  opacity: 0;
  
  /*  Enumerate transitioning properties, 
      including display and allow-discrete mode */
  transition: transform 0.5s, opacity 0.5s, display 0.5s allow-discrete;
}

overlay struttura

Infine, per far scomparire un elemento popover o dialog dal livello superiore, aggiungi la proprietà overlay al tuo elenco di transizioni. popover e dialog eseguono l'escape dei clip dei predecessori e delle trasformazioni e inseriscono i contenuti nel livello superiore. Se non esegui la transizione di overlay, il tuo elemento tornerà immediatamente a essere troncato, trasformato e coperto e non vedrai la transizione accadere.

[open] {
  transition: opacity 1s, display 1s allow-discrete;
}

Includi overlay nella transizione o nell'animazione per creare l'animazione di overlay insieme al resto delle funzionalità e assicurarti che rimanga nel livello superiore durante l'animazione. Il risultato sarà molto più fluido.

[open] {
  transition: opacity 1s, display 1s allow-discrete, overlay 1s allow-discrete;
}

Inoltre, quando più elementi sono aperti nel livello superiore, l'overlay consente di controllare la transizione fluida da e verso il livello superiore. Puoi notare la differenza in questo semplice esempio. Se non applichi overlay al secondo popover durante la transizione, verrà spostato prima dal livello superiore, saltando dietro l'altro popover, prima di iniziare la transizione. Questo non è un effetto molto uniforme.

Nota sulle transizioni delle visualizzazioni

Se stai apportando modifiche al DOM, ad esempio aggiungendo e rimuovendo elementi dal DOM, un'altra ottima soluzione per animazioni fluide è le transizioni di visualizzazione. Ecco due degli esempi precedenti creati utilizzando le transizioni delle viste.

In questa prima demo, invece di configurare @starting-style e altre trasformazioni CSS, verranno gestite le transizioni delle viste. La transizione della visualizzazione avviene nel seguente modo:

Innanzitutto, in CSS, assegna un view-transition-name a ogni scheda.

.card-1 {
  view-transition-name: card-1;
}

.card-2 {
  view-transition-name: card-2;
}

/* etc. */

Quindi, in JavaScript, aggrega la mutazione del DOM (in questo caso rimuovendo la scheda) in una transizione di visualizzazione.

deleteBtn.addEventListener('click', () => {
  // Check for browser support
  if (document.startViewTransition) {
    document.startViewTransition(() => {
      // DOM mutation
      card.remove();
    });
  } 
  // Alternative if no browser support
  else {
    card.remove();
  }
})

Ora il browser può gestire la dissolvenza in uscita e il morphing di ogni scheda nella nuova posizione.

Un altro esempio di questa funzionalità è la demo di aggiunta/rimozione di elementi dall'elenco. In questo caso, dovrai ricordarti di aggiungere un view-transition-name univoco per ogni scheda creata.

Conclusione

Queste nuove funzionalità della piattaforma ci avvicinano a un'animazione fluida di accesso e uscita sulla piattaforma web. Per saperne di più, dai un'occhiata a questi link: