Vier neue CSS-Funktionen für flüssige Einstiegs- und Exit-Animationen

Arhar
Joey Arhar

Bewegung ist ein zentraler Bestandteil jeder digitalen User Experience. Sie führt Nutzende von einer Interaktion zur nächsten. Auf der Webplattform gibt es jedoch einige Lücken bei den flüssigen Animationen. Dazu gehört die einfache Animation von Einstiegs- und Exit-Animationen sowie eine reibungslose Animation zur und von der obersten Ebene für Elemente, die geschlossen werden können, wie Dialogfelder und Pop-over.

Um diese Lücken zu schließen, gibt es in Chrome 116 und 117 vier neue Webplattformfunktionen, die flüssige Animationen und Übergänge für eigenständige Eigenschaften ermöglichen.

Zu diesen vier neuen Funktionen gehören:

  • Die Möglichkeit, display und content-visibility auf einer Keyframe-Zeitachse zu animieren (ab Chrome 116).
  • Die Eigenschaft transition-behavior mit dem Schlüsselwort allow-discrete, um Übergänge einzelner Eigenschaften wie display (aus Chrome 117) zu ermöglichen.
  • Die @starting-style-Regel zum Animieren von Eintragseffekten aus display: none in die oberste Ebene (aus Chrome 117).
  • Die Eigenschaft overlay zum Steuern des Verhaltens der obersten Ebene während einer Animation (ab Chrome 117). ## Animationen in Keyframes anzeigen

Ab Chrome 116 können Sie display und content-visibility in Keyframe-Regeln verwenden. Diese werden dann gewechselt, wenn der Keyframe erscheint. Es sind keine zusätzlichen neuen Werte erforderlich, um dies zu unterstützen:

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

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

Im vorherigen Beispiel wird die Deckkraft während der Dauer von 0,5 Sekunden auf 0 auf 0 gesetzt und dann „Keine“ angezeigt. Außerdem sorgt das Keyword forwards dafür, dass die Animation in ihrem Endzustand verbleibt, sodass das Element, auf das sie angewendet wird, display: none und opacity: 0 bleibt.

Dies ist ein einfaches Beispiel, das die Möglichkeiten mit einem Übergang darstellt (siehe Demo im Abschnitt zur Umstellung). Komplexere Animationen wie im folgenden Beispiel sind mit Übergängen jedoch nicht möglich:

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

Die spin-and-delete-Animation ist eine Exit-Animation. Zuerst dreht sich die Karte um die Y-Achse, durchläuft eine Farbtonrotation und wechselt dann bei 80% durch die Zeitachse, um ihre Deckkraft von 1 auf 0 zu ändern. Schließlich wird die Karte von display: block in display: none geändert.

Statt diese Exit-Animationen direkt auf ein Element anzuwenden, können Sie einen Trigger für die Animationen einrichten. Sie können beispielsweise einen Event-Listener an eine Schaltfläche anhängen, die eine Klasse zum Anwenden der Animation auslöst. Das sieht dann so aus:

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

Das obige Beispiel hat jetzt den Endzustand display:none. In vielen Fällen können Sie noch einen Schritt weitergehen und den DOM-Knoten mit einer Zeitüberschreitung entfernen, damit die Animation zuerst beendet wird.

Diskrete Animationen wechseln

Anders als bei der Animation einzelner Eigenschaften mit Keyframes müssen Sie für den Übergang einzelner Eigenschaften den Übergangsmodus allow-discrete verwenden.

Das Attribut transition-behavior

Der allow-discrete-Modus ermöglicht diskrete Übergänge und ist ein Wert des Attributs transition-behavior. transition-behavior akzeptiert zwei Werte: normal und 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;
}
Hinweis: Diese Übergangsdemo zeigt ein anderes Verfahren als die erste Animationsdemo, sieht aber optisch ähnlich aus.

Das Kürzel transition legt diesen Wert ebenfalls fest, sodass Sie die Eigenschaft weglassen und stattdessen das Schlüsselwort allow-discrete am Ende der Kurzschreibweise transition für jeden Übergang verwenden können.

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

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

Wenn Sie mehrere eigenständige Eigenschaften animieren, müssen Sie allow-discrete nach jeder Eigenschaft einfügen, die Sie animieren möchten. Beispiel:

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

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

Die @starting-style-Regel für Eingabeanimationen

Bisher wurden in diesem Artikel Exit-Animationen behandelt. Zum Erstellen von Einstiegsanimationen benötigen Sie die Regel @starting-style.

Mit @starting-style können Sie einen Stil anwenden, den der Browser aufrufen kann, bevor das Element auf der Seite geöffnet wird. Dies ist der Zustand „before_open“, also der Zustand, von dem aus Sie die Animation starten.

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

Jetzt haben Sie sowohl einen Eingabe- als auch einen Exit-Status für diese ToDo-Listenelemente:

Elemente zur obersten Ebene und von der obersten Ebene animieren

Wenn Sie Elemente zur obersten Ebene bzw. von der obersten Ebene animieren möchten, geben Sie @starting-style im Status „geöffnet“ an. So wird dem Browser mitgeteilt, von wo aus die Animation gestartet werden soll. Bei einem Dialogfeld wird der geöffnete Zustand mit dem Attribut [open] definiert. Für ein Popover verwenden Sie die Pseudoklasse :popover-open.

Ein einfaches Beispiel für einen Dialog könnte so aussehen:

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

Im nächsten Beispiel unterscheiden sich die Einstiegs- und Exit-Effekte. Betreten Sie den Darstellungsbereich, indem Sie vom unteren Rand des Darstellungsbereichs nach oben animiert werden. Beenden Sie den Effekt bis zum oberen Rand des Darstellungsbereichs. Er ist außerdem mit verschachteltem CSS-Code geschrieben, um eine bessere visuelle Kapselung zu ermöglichen.

Verwende bei der Animation eines Pop-over die Pseudoklasse :popover-open anstelle des zuvor verwendeten open-Attributs.

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

Wenn Sie schließlich popover oder dialog von der obersten Ebene ausblenden möchten, fügen Sie der Liste der Übergänge die Eigenschaft overlay hinzu. popover und dialog maskieren Ancestor-Clips und -Transformationen und platzieren den Inhalt auf der obersten Ebene. Wenn Sie overlay nicht übergehen, wird das Element sofort wieder zugeschnitten, umgewandelt und verdeckt und Sie können den Übergang nicht sehen.

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

Fügen Sie stattdessen overlay in den Übergang oder in die Animation ein, um overlay zusammen mit den anderen Funktionen zu animieren, damit es bei Animationen auf der obersten Ebene bleibt. Das sieht viel reibungsloser aus.

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

Wenn Sie in der oberen Ebene mehrere Elemente geöffnet haben, können Sie mithilfe von Overlay-Anzeigen außerdem den sanften Übergang in die oberste Ebene und aus der oberen Ebene steuern. In diesem einfachen Beispiel wird der Unterschied deutlich. Wenn Sie beim Übergang aus dem zweiten Pop-over overlay nicht auf das zweite Pop-over anwenden, wird es zuerst aus dem oberen Layer herausgezogen, sodass es hinter dem anderen Pop-over springt, bevor mit dem Übergang begonnen wird. Das ist kein sehr sanfter Effekt.

Hinweis zu Ansichtsübergängen

Wenn Sie DOM-Änderungen vornehmen, zum Beispiel Elemente hinzufügen oder aus dem DOM entfernen, sind Ansichtsübergänge eine weitere großartige Lösung für flüssige Animationen. Hier sehen Sie zwei der obigen Beispiele, die mit Ansichtsübergängen erstellt wurden.

In dieser ersten Demo wird der Übergang nicht von @starting-style und anderen CSS-Transformationen eingerichtet, sondern von Ansichtsübergängen. Der Ansichtsübergang wird so eingerichtet:

Weisen Sie in der CSS zuerst jeder Karte eine individuelle view-transition-name zu.

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

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

/* etc. */

Fassen Sie dann in JavaScript die DOM-Mutation (in diesem Fall das Entfernen der Karte) in einem Ansichtsübergang um.

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

Jetzt kann der Browser das Ausblenden und Morphen jeder Karte an ihre neue Position durchführen.

Ein weiteres Beispiel, in dem dies praktisch sein kann, ist die Demo zum Hinzufügen/Entfernen von Listenelementen. In diesem Fall musst du für jede erstellte Karte eine eindeutige view-transition-name hinzufügen.

Fazit

Diese neuen Plattformfunktionen bringen uns dem reibungslosen Ein- und Beenden von Animationen auf der Webplattform einen Schritt näher. Weitere Informationen findest du unter den folgenden Links: