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 entrata 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). Tuttavia, le transizioni 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.

Transizioni di animazioni distinte

A differenza dell'animazione di proprietà discrete con i fotogrammi chiave, per applicare transizioni a proprietà discrete devi utilizzare la modalità di comportamento di transizione allow-discrete.

La proprietà transition-behavior

La modalità allow-discrete rende possibili le transizioni discrete ed è 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 la scorciatoia transition imposta questo valore, quindi puoi omettere la proprietà e utilizzare la parola chiave allow-discrete alla fine della scorciatoia transition per ogni transizione.

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

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

Se stai animando più proprietà distinte, devi includere allow-discrete dopo ogni proprietà da 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 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 "aperto" 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. Inserisci l'animazione dall'alto verso il basso della visualizzazione e esci dall'effetto verso la parte superiore della visualizzazione. Inoltre, è scritto con CSS nidificato per una maggiore incapsulamento visivo.

Quando animi un popup, utilizza la pseudo classe :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: