Quatre nouvelles fonctionnalités CSS pour des animations d'entrée et de sortie fluides

Le mouvement est un élément essentiel de toute expérience numérique. Il guide l'utilisateur d'une interaction à l'autre. Toutefois, les animations fluides sur la plate-forme Web présentent quelques lacunes. Vous pouvez ainsi animer facilement les animations d'entrée et de sortie, et animer de manière fluide les éléments pouvant être fermés, tels que les boîtes de dialogue et les popovers, vers et depuis la couche supérieure.

Pour combler ces lacunes, Chrome 116 et 117 incluent quatre nouvelles fonctionnalités de plate-forme Web, qui permettent d'animer et de faire des transitions fluides pour des propriétés distinctes.

Voici les quatre nouvelles fonctionnalités:

  • Possibilité d'animer display et content-visibility sur une timeline de clés-images (à partir de Chrome 116).
  • La propriété transition-behavior avec le mot clé allow-discrete pour activer les transitions de propriétés distinctes telles que display (à partir de Chrome 117).
  • Règle @starting-style pour animer les effets d'entrée à partir de display: none et dans la couche supérieure (à partir de Chrome 117).
  • La propriété overlay permet de contrôler le comportement de la couche supérieure pendant une animation (à partir de Chrome 117).

Afficher des animations dans des images clés

À partir de Chrome 116, vous pouvez utiliser display et content-visibility dans les règles de clés-images. Ils seront ensuite remplacés au moment de l'apparition de la clé-image. Aucune nouvelle valeur n'est requise pour cela:

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

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

L'exemple précédent définit l'opacité sur 0 pendant 0,5 s, puis définit l'affichage sur "none". En outre, le mot clé forwards garantit que l'animation reste à son état final, de sorte que l'élément auquel elle est appliquée reste display: none et opacity: 0.

Il s'agit d'un exemple simple qui imite ce que vous pouvez faire avec une transition (voir la démonstration dans la section "Transition"). Toutefois, les transitions ne permettent pas de créer des animations plus complexes, comme dans l'exemple suivant:

.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'animation spin-and-delete est une animation de sortie. Tout d'abord, la fiche tourne sur l'axe Y, subit une rotation de teinte, puis à 80% dans la timeline, son opacité passe de 1 à 0. Enfin, la carte passe de display: block à display: none.

Pour ces animations de sortie, au lieu de les appliquer directement à un élément, vous pouvez configurer un déclencheur pour les animations. Par exemple, en associant un écouteur d'événements à un bouton qui déclenche une classe pour appliquer l'animation, comme suit:

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

L'exemple ci-dessus a désormais un état final de display:none. Dans de nombreux cas, vous souhaiterez aller plus loin et supprimer le nœud DOM avec un délai avant expiration pour permettre à l'animation de se terminer en premier.

Transférer des propriétés distinctes

Les propriétés qui s'animent de manière discrète ne déclenchent pas d'événements de transition par défaut. Pour l'activer, définissez le mode de comportement de transition sur allow-discrete.

Propriété transition-behavior

La propriété transition-behavior indique si des transitions seront lancées ou non pour des propriétés distinctes. Il accepte deux valeurs: normal et allow-discrete, la valeur initiale étant normal.

  • normal: les transitions ne seront pas lancées pour les propriétés discrètes, mais uniquement pour les propriétés interpolables.
  • allow-discrete: les transitions seront lancées pour les propriétés discrètes et les propriétés interpolables.

Pour activer le mode allow-discrete pour une propriété spécifique, incluez-la dans l'abréviation 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;
}
Remarque: Cette démonstration de transition utilise une technique différente de la première animation, mais est visuellement similaire.

Lorsque vous effectuez une transition entre plusieurs propriétés distinctes, vous devez définir allow-discrete pour chaque propriété en transition. Exemple :

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

Pour définir le comportement de toutes les propriétés en transition, déclarez transition-behavior: allow-discrete après la déclaration transition. Il s'agit souvent de l'approche la plus simple.

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

Règle @starting-style pour les animations d'entrée

Jusqu'à présent, cet article a traité des animations de sortie. Pour créer des animations d'entrée, vous devez utiliser la règle @starting-style.

Utilisez @starting-style pour appliquer un style que le navigateur peut rechercher avant que l'élément ne s'ouvre sur la page. Il s'agit de l'état "avant ouverture" (à partir duquel vous animez l'élément).

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

Vous disposez désormais d'un état d'entrée et de sortie pour ces éléments de la liste de tâches à effectuer:

Animer des éléments vers et depuis la couche supérieure

Pour animer des éléments vers et depuis la couche supérieure, spécifiez @starting-style dans l'état "ouvert" pour indiquer au navigateur à partir de quel élément l'animation doit commencer. Pour une boîte de dialogue, l'état ouvert est défini avec l'attribut [open]. Pour un popover, utilisez la pseudo-classe :popover-open.

Voici un exemple simple de boîte de dialogue:

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

Dans l'exemple suivant, les effets d'entrée et de sortie sont différents. Commencez l'animation en partant du bas de la fenêtre d'affichage et terminez-la en haut de la fenêtre d'affichage. Il est également écrit avec du CSS imbriqué pour une encapsulation visuelle plus efficace.

Lorsque vous animez un popover, utilisez la pseudo-classe :popover-open au lieu de l'attribut open utilisé précédemment.

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

Enfin, pour faire disparaître un popover ou un dialog de la couche supérieure, ajoutez la propriété overlay à votre liste de transitions. popover et dialog échappent aux clips et aux transformations des ancêtres, et placent également le contenu dans la couche supérieure. Si vous ne définissez pas de transition overlay, votre élément sera immédiatement à nouveau rogné, transformé et masqué, et vous ne verrez pas la transition.

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

Incluez plutôt overlay dans la transition ou l'animation pour animer overlay avec le reste des éléments et vous assurer qu'il reste dans la couche supérieure lors de l'animation. Le résultat sera beaucoup plus fluide.

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

De plus, lorsque plusieurs éléments sont ouverts dans la couche supérieure, la superposition vous aide à contrôler la transition fluide entre la couche supérieure et les autres couches. Vous pouvez voir la différence dans cet exemple simple. Si vous n'appliquez pas overlay au deuxième popover lors de sa sortie, il quittera d'abord la couche supérieure, en s'arrêtant derrière l'autre popover, avant de commencer la transition. Ce n'est pas un effet très fluide.

Remarque concernant les transitions de vue

Si vous apportez des modifications au DOM, par exemple en ajoutant et en supprimant des éléments, les transitions de vue constituent une autre excellente solution pour des animations fluides. Voici deux des exemples ci-dessus créés à l'aide de transitions de vue.

Dans cette première démonstration, au lieu de configurer @starting-style et d'autres transformations CSS, les transitions de vue géreront la transition. La transition de vue est configurée comme suit:

Tout d'abord, dans CSS, attribuez un view-transition-name individuel à chaque fiche.

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

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

/* etc. */

Ensuite, en JavaScript, encapsulez la mutation DOM (dans ce cas, la suppression de la fiche) dans une transition de vue.

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

Le navigateur peut désormais gérer l'atténuation et la transformation de chaque fiche vers sa nouvelle position.

Un autre exemple où cela peut être utile est la démonstration d'ajout/suppression d'éléments de liste. Dans ce cas, vous devez penser à ajouter un view-transition-name unique pour chaque fiche créée.

Conclusion

Ces nouvelles fonctionnalités de la plate-forme nous rapprochent de l'objectif d'animations d'entrée et de sortie fluides sur la plate-forme Web. Pour en savoir plus, consultez les liens suivants: