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

Il movimento è una parte fondamentale di qualsiasi esperienza digitale e guida l'utente da un'interazione all'altra. Tuttavia, ci sono alcune lacune nelle animazioni fluide sulla piattaforma web. Sono incluse la possibilità di animare facilmente le animazioni di entrata e di uscita e di animare senza interruzioni verso e dal livello superiore per gli elementi ignorabili, come finestre di dialogo e popup.

Per colmare queste lacune, Chrome 116 e 117 includono quattro nuove funzionalità della piattaforma web che consentono animazioni e transizioni fluide per proprietà distinte.

Queste quattro nuove funzionalità includono:

  • La possibilità di animare display e content-visibility in una sequenza temporale dei fotogrammi chiave (da Chrome 116).
  • La proprietà transition-behavior con la parola chiave allow-discrete per abilitare le transizioni di proprietà discrete come display (da Chrome 117).
  • La regola @starting-style per animare gli effetti di inserimento 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 le animazioni nei fotogrammi chiave

A partire da Chrome 116, puoi utilizzare display e content-visibility nelle regole delle keyframe. Verranno scambiati al momento in cui si verifica la keyframe. Non sono necessari nuovi valori per supportare questa funzionalità:

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

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

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

Questo è un semplice esempio che mostra cosa puoi fare con una transizione (vedi la demo nella sezione relativa alle transizioni). Le transizioni, tuttavia, non sono in grado 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. Innanzitutto, la scheda ruota sull'asse Y, esegue una rotazione di tonalità e, al punto 80% della sequenza temporale, la sua opacità passa da 1 a 0. Infine, la scheda passa da display: block a display: none.

Per queste animazioni di uscita, invece di applicarle direttamente a un elemento, puoi configurare un attivatore per le animazioni. Ad esempio, collegando un gestore di eventi a un pulsante che attiva una classe per applicare l'animazione, come segue:

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

L'esempio riportato sopra ora ha uno stato finale di display:none. In molti casi è consigliabile andare oltre e rimuovere il nodo DOM con un timeout per consentire il completamento dell'animazione.

Transizione di proprietà distinte

Le proprietà animate in modo discreto non attivano gli eventi di transizione per impostazione predefinita. Per attivare questa opzione, imposta la modalità di comportamento di transizione su allow-discrete.

La proprietà transition-behavior

La proprietà transition-behavior specifica se le transizioni verranno avviate o meno per le proprietà distinte. Accetta due valori: normal e allow-discrete, con il valore iniziale normal.

  • normal: le transizioni non verranno avviate per le proprietà discrete, ma solo per quelle interpolabili.
  • allow-discrete: le transizioni verranno avviate per le proprietà discrete e per quelle interpolabili.

Per attivare la modalità allow-discrete per una proprietà specifica, includila nella scorciatoia transition:

.card {
  transition: opacity 0.25s, display 0.25s allow-discrete; /* Enable allow-discrete for the display property */
}

.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.

Quando esegui la transizione di più proprietà distinte, devi impostare allow-discrete per ogni proprietà in transizione. Ad esempio:

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

In alternativa, per impostare il comportamento per tutte le proprietà in transizione, dichiara transition-behavior: allow-discrete dopo la dichiarazione transition. Spesso si tratta dell'approccio più semplice.

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

La regola @starting-style per le animazioni di entrata

Finora questo articolo ha trattato 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 venga aperto nella pagina. Questo è lo stato "prima dell'apertura" (da dove parte l'animazione).

/*  0. 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;
}

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

/*  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 uno di uscita per questi elementi dell'elenco TO DO:

Animazione di elementi verso e dal livello superiore

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

Un semplice esempio di finestra di dialogo potrebbe avere il seguente aspetto:

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

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

/*   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;
}

Nell'esempio seguente, gli effetti di entrata e di uscita sono diversi. Entra animando verso l'alto dalla parte inferiore dell'area visibile ed esci dall'effetto nella parte superiore dell'area visibile. Inoltre, è scritto con CSS nidificato per una maggiore incapsulamento visivo.

Quando animi un popup, utilizza la pseudoclasse :popover-open anziché l'attributo open utilizzato in precedenza.

.settings-popover {
  &:popover-open {
    /*  0. IS-OPEN STATE  */
    /*  state when popover is open, BOTH:
        what we're transitioning *in* to 
        and transitioning *out* from */
    transform: translateY(0);
    opacity: 1;

    /*  1. 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;
    }
  }
  
  /*  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 attenuare un popover o un dialog dal livello superiore, aggiungi la proprietà overlay all'elenco delle transizioni. popover e dialog escono dai clip e dalle trasformazioni degli antenati e inseriscono i contenuti nel livello superiore. Se non esegui la transizione overlay, l'elemento tornerà immediatamente a essere ritagliato, trasformato e coperto e non vedrai la transizione.

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

Includi invece overlay nella transizione o nell'animazione per animarlo insieme alle altre funzionalità e assicurati che rimanga nel livello superiore durante l'animazione.overlay Il risultato sarà molto più fluido.

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

Inoltre, quando hai più elementi aperti nel livello superiore, l'overlay ti aiuta a controllare la transizione fluida all'interno e all'esterno del livello superiore. Puoi vedere la differenza in questo semplice esempio. Se non applichi overlay al secondo popup durante la transizione, prima uscirà dal livello superiore, passando dietro l'altro popup, prima di iniziare la transizione. Non è un effetto molto fluido.

Una nota sulle transizioni di visualizzazione

Se apporti modifiche al DOM, ad esempio aggiungi e rimuovi elementi dal DOM, un'altra ottima soluzione per animazioni fluide è rappresentata dalle transizioni di visualizzazione. Ecco due degli esempi precedenti creati utilizzando le transizioni di visualizzazione.

In questa prima demo, invece di impostare @starting-style e altre trasformazioni CSS, le transizioni di visualizzazione gestiranno la transizione. La transizione di visualizzazione è configurata nel seguente modo:

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

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

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

/* etc. */

Poi, in JavaScript, inserisci la mutazione DOM (in questo caso, la rimozione della 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 l'attenuazione e la trasformazione di ogni scheda nella nuova posizione.

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

Conclusione

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