mitmario.dev

Übergänge aus dem Nichts

CSS Im Browser 2 Min Lesezeit 2 BeispieleLektion 7 von 8

Ein Element, das gerade erst entstanden ist, lässt sich nicht animieren, weil es keinen Zustand hat, von dem aus ein Übergang losgehen könnte. Wer eine Meldung nach dem Speichern, ein Menü oder ein Popover weich einblenden wollte, brauchte dafür bis vor kurzem JavaScript.

Gebraucht wird das an allem, was zwischen display: none und sichtbar wechselt: an einem Dialog, an einem Popover, an einem Menü, an einer Meldung, die erst nach einem Klick dasteht. Überall dort gibt es vor dem ersten Bild keinen Wert, von dem aus ein Übergang loslaufen könnte, und diesen Wert liefert die Regel aus dieser Lektion.

@starting-style können alle großen Browser seit August 2024. Nur lässt Firefox display bisher nicht übergehen, dort springt das Ausblenden, und das Einblenden läuft trotzdem weich.

Ein Zustand für das erste Bild

Der Startzustand für das erste Bild
body {
  margin: 0;
  padding: 24px;
  font-family: system-ui, sans-serif;
  line-height: 1.5;
}

.schalter {
  position: absolute;
  opacity: 0;
}

.knopf {
  display: inline-block;
  margin-bottom: 12px;
  padding: 8px 16px;
  border-radius: 8px;
  color: #ffffff;
  background-color: #2563eb;
  cursor: pointer;
}

.hinweis {
  display: none;
  opacity: 0;
  translate: 0 -8px;
  max-width: 320px;
  padding: 16px;
  border-radius: 8px;
  background-color: #f4f4f5;

  transition-property: opacity, translate, display;
  transition-duration: 0.3s;
  transition-timing-function: ease-out;
  /* Ohne diese Zeile springt display und der
     Kasten ist sofort weg. */
  transition-behavior: allow-discrete;
}

.schalter:checked ~ .hinweis {
  display: block;
  opacity: 1;
  translate: 0 0;
}

/* Der Zustand für das allererste Bild, in dem es
   den Kasten überhaupt gibt. */
@starting-style {
  .schalter:checked ~ .hinweis {
    opacity: 0;
    translate: 0 -8px;
  }
}

Ein Übergang braucht zwei Werte. Wenn ein Element von display: none kommt, gab es vorher gar keinen, und der Browser hatte nichts zu interpolieren.

@starting-style liefert diesen fehlenden Wert. Der Block beschreibt, wie das Element im allerersten Bild aussieht, in dem es dasteht. Ab dem zweiten gilt wieder die normale Regel, und dazwischen läuft der Übergang.

Auf die Reihenfolge kommt es dabei an. Der Block muss nach der Regel stehen, deren Startwerte er liefert, oder in ihr verschachtelt. Steht er davor, gewinnt die normale Regel, und der Übergang läuft nicht. Im Beispiel steht er deshalb ganz unten.

Dazu gehört eine zweite Angabe. display kennt keine Zwischenwerte, es ist entweder none oder etwas anderes. transition-behavior: allow-discrete erlaubt trotzdem einen Übergang darauf, und Chrome, Edge und Safari halten das Element dann bis zum Ende sichtbar, statt es sofort verschwinden zu lassen. Firefox lässt es bisher sofort verschwinden. Beides zusammen nimmt dem Weg aus Lektion 13.5 seinen Haken. Dort musste das Menü im Layout stehen bleiben, nur zusammengeklappt, weil zwischen none und block nichts liegt. Mit allow-discrete liegt jetzt etwas dazwischen.

Derselbe Kasten ohne Startzustand
body {
  margin: 0;
  padding: 24px;
  font-family: system-ui, sans-serif;
  line-height: 1.5;
}

.schalter {
  position: absolute;
  opacity: 0;
}

.knopf {
  display: inline-block;
  margin-bottom: 12px;
  padding: 8px 16px;
  border-radius: 8px;
  color: #ffffff;
  background-color: #2563eb;
  cursor: pointer;
}

.hinweis {
  display: none;
  opacity: 0;
  translate: 0 -8px;
  max-width: 320px;
  padding: 16px;
  border-radius: 8px;
  background-color: #f4f4f5;

  transition-property: opacity, translate, display;
  transition-duration: 0.3s;
  transition-timing-function: ease-out;
  transition-behavior: allow-discrete;
}

/* Hier fehlt der @starting-style-Block. Das
   Einblenden springt deshalb, das Ausblenden
   läuft trotzdem weich. */
.schalter:checked ~ .hinweis {
  display: block;
  opacity: 1;
  translate: 0 0;
}

Einmal auf- und wieder zugeklickt, zeigt das zweite Beispiel, was ohne Startzustand passiert. Das Einblenden springt, das Ausblenden läuft weich. Dieser halbe Effekt erinnert an den falsch gesetzten Übergang in Lektion 13.1, nur andersherum und aus einem anderen Grund.

Dieselbe Idee für den Wechsel zwischen zwei Seiten heißt View Transitions: Der Browser kennt die alte und die neue Seite und blendet zwischen ihnen über.

In der Aufgabe erscheint eine Meldung nach einem Klick auf „Speichern“, bisher ohne jeden Übergang.

Zum Mitnehmen

@starting-style liefert den Wert für das erste Bild eines Elements, damit ein Übergang auch beim Erscheinen läuft. Der Block steht nach der Regel, deren Startwerte er liefert, und für display braucht es dazu transition-behavior: allow-discrete.

Jetzt du

Basis Konto, kostenlos

Zu dieser Lektion gehört eine Aufgabe. Du schreibst den Code selbst, und nach jedem Lauf sagt dir eine Prüfliste, was schon stimmt.

Dafür brauchst du das Basis Konto. Es kostet nichts, und ein Passwort gibt es auch nicht.

Was in dieser Lektion steckt

  • Artikel mit 2 Beispielen zum Ausprobieren

    Steht hier, ohne Konto lesbar.

  • Aufgabe im Editor, direkt im Browser geprüft

    Öffnet sich mit dem Basis Konto.