Dieser Inhalt wurde automatisch aus dem Englischen übersetzt, und kann Fehler enthalten. Erfahre mehr über dieses Experiment.

View in English Always switch to English

Verwendung von elementspezifischen View-Transitions

Elementspezifische View-Transitions sind auf einen bestimmten DOM-Teilbaum eines Elements beschränkt. Sie bieten viele Vorteile gegenüber dokumentenspezifischen View-Transitions: Sie können Übergänge auf Unterabschnitten des Dokuments anwenden, während der Rest interaktiv bleibt, mehrere Übergänge gleichzeitig ausführen — einschließlich verschachtelter Übergänge — und verschiedene andere Probleme lösen.

Dieser Artikel behandelt, wie elementspezifische View-Transitions funktionieren und wie man sie verwendet.

Hinweis: "Dokumentenspezifische View-Transitions" beziehen sich auf gleiche Dokumentenübergänge, also Übergänge, die über die Methode Document.startViewTransition() initiiert werden.

Elementspezifische View-Transitions werden über die gleiche Methode gestartet, die auf einem einzelnen Element aufgerufen wird (siehe Element.startViewTransition()). Elementspezifische View-Transitions sind nicht für dokumentübergreifende Übergänge verfügbar.

Probleme mit dokumentenspezifischen View-Transitions

Dokumentenspezifische View-Transitions sind nützlich, um DOM-Inhaltsaktualisierungen über ein ganzes Dokument hinweg zu animieren. Sie können verschiedene Animationen auf verschiedene Teile der Seite anwenden, eine einzige Übergangsanimation auf die gesamte Seite oder keine Animationen.

Sie können auch verschiedene View-Transition-Typen verwenden, um je nach Umstand unterschiedliche Animationen auf das gleiche Element anzuwenden - zum Beispiel, ob es das nächste oder vorherige Element in einer Sequenz ist.

Allerdings haben dokumentenspezifische View-Transitions mehrere Nachteile:

  • Sie können nicht mehr als eine View-Transition gleichzeitig ausführen.
  • Wenn ein View-Transition läuft, ist die Seite nicht interaktiv, bis der Übergang abgeschlossen ist.
  • Der Pseudoelement-Baum, der mit einer dokumentenspezifischen View-Transition verbunden ist, liegt über allem anderen auf der Seite. Wenn ein anderes Element über dem aktualisierenden Teil der Seite positioniert ist, wenn die Übergangsanimation startet (zum Beispiel durch Verwendung von z-index), verschwindet das positionierte Element während der Dauer der Animation unter dem Übergang, was wahrscheinlich nicht der gewünschte Effekt ist.
  • In Bezug auf das vorherige Problem: Wenn der aktualisierende Teil der Seite von einem übergeordneten Wrapper mit overflow abgeschnitten wird, wird er beim Start der Animation aus dem Container herausragen.

Elementspezifische View-Transitions können diese Probleme lösen. Schauen wir uns einige Beispiele an, um zu sehen, wie das funktioniert.

Grundlegendes elementspezifisches Beispiel

Dieses Beispiel enthält eine Liste von Links. Wenn ein Link angeklickt wird, ändert sich sein Inhalt und diese Änderung wird durch eine elementspezifische View-Transition animiert. Das Beispiel enthält auch ein Element, das das übergehende Element leicht überlappt; wir verwenden dies, um zu zeigen, wie z-index-Probleme vermieden werden können.

HTML

Das Markup enthält eine <ul>-Liste von Links zwischen zwei <p>-Elementen, die Textinhalte enthalten.

html
<p>
  I'm baby xOXO bespoke cupidatat PBR&B, affogato cronut 3 wolf moon ea narwhal
  asymmetrical.
</p>

<ul>
  <li><a href="#">Standard</a></li>
  <li><a href="#">Standard</a></li>
  <li><a href="#">Standard</a></li>
  <li><a href="#">Standard</a></li>
</ul>

<p>
  Kombucha laborum tempor iceland pour-over. Keytar in echo park gorpcore
  bespoke.
</p>

CSS

Wir beginnen damit, dem <ul> einen Hintergrund und eine border-Stilisierung zu geben. Wir geben ihm auch eine position von relative, sodass wir Nachkommen relativ zum <ul> absolut positionieren können.

css
ul {
  border: 2px solid #999;
  background: #ccc;
  position: relative;
}

Als nächstes geben wir den <a>-Elementen ihre eigenen border-Stile und wenden eine transition an, sodass Aktualisierungen des border-Stils bei Zustandsänderungen sanft animiert werden. Bei :hover und :focus ändern wir die Link-border-color zu black.

css
a {
  border: 2px solid #aaa;
  transition: border 0.6s;
}

a:hover,
a:focus {
  border-color: black;
}

Der relevanteste CSS-Code für View-Transitions definiert benutzerdefinierte animation-Einstellungen für die old und new Transition-Zustände, die den alten DOM-Zustand herausrotieren und den neuen DOM-Zustand hereinrotieren. Beachten Sie, dass wir einen animation-delay-Wert auf die rotate-in-Animation angewendet haben (der zweite 0.3s-Wert), um sicherzustellen, dass sie nur dann startet, wenn die rotate-out-Animation endet.

css
::view-transition-old(*) {
  animation: rotate-out 0.3s 1 both linear;
}

::view-transition-new(*) {
  animation: rotate-in 0.3s 0.3s 1 both linear;
}

@keyframes rotate-out {
  from {
    rotate: 0deg x;
  }

  to {
    rotate: 90deg x;
  }
}

@keyframes rotate-in {
  from {
    rotate: -90deg x;
  }

  to {
    rotate: 0deg x;
  }
}

Abschließend erstellen wir einige generierte Inhalte auf dem <ul>-Element mithilfe des ::before-Pseudoelements und positionieren es über dem <ul>-Element. Der generierte Inhalt enthält einen transparenten Verlaufs-Effekt.

css
ul::before {
  content: "";
  position: absolute;
  top: 0;
  bottom: 0;
  left: -5px;
  width: 100px;
  background-image: linear-gradient(
    to right,
    rgb(255 255 255),
    rgb(255 255 255) 25%,
    rgb(255 255 255 / 0)
  );
  z-index: 1;
}

JavaScript

Im Skript holen wir uns eine Referenz auf das <ul>-Element und fügen ihm einen click-Event-Listener hinzu. Wenn es angeklickt wird, prüfen wir, ob das Ereignisziel ein <a>-Element ist. Falls ja, rufen wir startViewTransition() auf dem angeklickten <a>-Element auf und wechseln seinen Inhalt zwischen "Standard" und "Alternative" durch die toggleText()-Funktion.

Beachten Sie, dass wir auch eine Funktionsprüfung eingefügt haben, um sicherzustellen, dass der Code in Browsern funktioniert, die startViewTransition() nicht unterstützen: Bevor startViewTransition() ausgeführt wird, prüfen wir, ob es auf dem Zielelement existiert. Wenn nicht, führen wir einfach die toggleText()-Funktion aus und return, sodass das DOM trotzdem aktualisiert wird, aber ohne die Übergangsanimation.

js
const list = document.querySelector("ul");

list.addEventListener("click", handleClick);

function handleClick(e) {
  function toggleText() {
    if (e.target.textContent === "Standard") {
      e.target.textContent = "Alternative";
    } else {
      e.target.textContent = "Standard";
    }
  }
  if (e.target.tagName === "A") {
    if (!e.target.startViewTransition) {
      toggleText();
      return;
    }
    e.target.startViewTransition(() => {
      toggleText();
    });
  }
}

Ergebnis

Klicken/Aktiveren Sie die Links, um die View-Transition auf jedem zu sehen.

Jedes <a>-Element hat seine eigene View-Transition, die nur auf dieses Element beschränkt ist. Der Rest der Seite bleibt während einer laufenden View-Transition interaktiv, sodass Sie mehrere View-Transitions gleichzeitig ausführen können. Darüber hinaus bleiben die sich überlappenden erzeugten Inhalte über den übergehenden Elementen.

Unterschiede zwischen element- und dokumentenspezifischen Übergängen

Das vorherige Beispiel zeigt, wie elementspezifische View-Transitions einige der Probleme ihrer dokumentenspezifischen Gegenstücke beheben. Dies ist größtenteils der unterschiedlichen Platzierung der Pseudoelement-Bäume zu verdanken. Anstatt dem :root-Element hinzugefügt zu werden, fügt der Browser elementspezifische View-Transition-Bäume dem Element hinzu, auf dem Element.startViewTransition() aufgerufen wird.

Im vorherigen Beispiel würde einer der Pseudoelement-Bäume so aussehen:

<a href="#">
  ├─ ::view-transition
  │  └─ ::view-transition-group(root)
  │     └─ ::view-transition-image-pair(root)
  │        ├─ ::view-transition-old(root)
  │        └─ ::view-transition-new(root)
  |
  |
  "Alternative"
</a>

Dies bedeutet, dass der Übergang auf das <a>-Element (als "Transition Root" oder "Scope" bezeichnet) und dessen DOM-Inhalte beschränkt ist, sodass er andere Elemente oder laufende View-Transitions nicht beeinträchtigt. Wenn die View-Transition startet, sucht der Browser nur innerhalb dieses Scopes nach Elementen, die in Schnappschüsse aufgenommen werden sollen. Während des Snapshot-Prozesses - bis das Versprechen ViewTransition.updateCallbackDone erfüllt ist - wird das Rendering nur innerhalb des Scopes angehalten.

Das ::view-transition-Pseudoelement hat die gleiche Größe und Form wie das Übergangselement und rendert nur darüber, nicht über den Rest der Seite. Dadurch wird die Layer-Reihenfolge von Elementen außerhalb des Übergangselements respektiert.

Selbstteilnahme von Scopes und Beschneidung

Ein weiteres wichtiges Merkmal von elementspezifischen View-Transitions ist, dass das übergehende Element, wenn es von seinem Container abgeschnitten wird (z. B. durch overflow: scroll), während der Übergangsanimation abgeschnitten bleibt.

Dies geschieht, weil auf dem Root-Element des Scopes automatisch Folgendes gesetzt wird:

Hinweis: Sie können einen View-Transition aus der Selbstteilnahme herausnehmen, indem Sie view-transition-name: none auf dem Übergangselement setzen. Dies kann jedoch zu unerwünschtem Verhalten führen, wie das Austreten des Übergangs aus dem Root-Element in Abschneidefällen. Wenn Sie dies tun, testen Sie sorgfältig und stellen Sie sicher, dass der Scope seine Inhalte nicht abschneidet.

Schauen wir uns ein weiteres Beispiel an, diesmal um das Abschneideverhalten zu demonstrieren.

HTML

Das HTML ähnelt dem vorherigen Beispiel, außer dass das zentrale Element jetzt ein <section> ist, das ein Absatz mit Text enthält. Wir fügen auch einen <button> hinzu, der gedrückt werden kann, um den Absatzinhalt zu ändern.

html
<p>
  I'm baby xOXO bespoke cupidatat PBR&B, affogato cronut 3 wolf moon ea narwhal
  asymmetrical.
</p>

<section>
  <p>
    I'm baby xOXO bespoke cupidatat PBR&B, affogato cronut 3 wolf moon ea
    narwhal asymmetrical. Af health goth shaman in slow-carb godard echo park.
    Tofu farm-to-table labore salvia tote bag food truck dolore gluten-free
    poutine kombucha fanny pack +1 franzen lyft fugiat. Chicharrones next level
    jianbing, enamel pin seitan cardigan bruh snackwave beard incididunt dolor
    lumber before they sold out dreamcatcher single-origin coffee.
  </p>
</section>
<button>Change!</button>

<p>
  Kombucha laborum tempor iceland pour-over. Keytar in echo park gorpcore
  bespoke.
</p>

CSS

Zunächst setzen wir eine feste height und overflow-y: scroll auf das <section>, damit der <p>-Inhalt vertikal scrollt.

css
section {
  height: 150px;
  overflow-y: scroll;
}

Als nächstes setzen wir ein view-transition-name auf das verschachtelte <p>-Element, mit übereinstimmenden Namen in den benutzerdefinierten ::view-transition-old() und ::view-transition-new() Pseudo-Elementen. Dies bedeutet, dass nur <p> animiert wird, nicht der Rest des Übergangs-Scopes.

css
section p {
  view-transition-name: content;
}

::view-transition-old(content) {
  animation: rotate-out 0.3s 1 both linear;
}

::view-transition-new(content) {
  animation: rotate-in 0.3s 0.3s 1 both linear;
}

Der Kürze halber ist der @keyframes Definitionscode verborgen. Er ist nahezu identisch mit dem vorherigen Beispiel; der einzige Unterschied besteht darin, dass die Rotation in diesem Beispiel um die y-Achse und nicht um die x-Achse erfolgt.

JavaScript

Das Script definiert ein content-Array, das zwei unterschiedliche Zeichenfolgen enthält, um den <p>-Inhalt zu wechseln. Wir holen uns dann Referenzen auf die <section>, <p>, und <button>-Elemente.

js
const content = ["I'm baby xOXO ...", "Kombucha laborum ..."];

const section = document.querySelector("section");
const para = document.querySelector("section p");
const btn = document.querySelector("button");

Als nächstes fügen wir dem <button> einen click-Event-Listener hinzu. Jedes Mal, wenn der Button angeklickt wird, wird eine View-Transition ausgelöst: Innerhalb des startViewTransition()-Aufrufs wird der textContent des <p>-Elements durch die toggleText()-Funktion zwischen den beiden content-Array-Elementen gewechselt. Wir haben auch eine einfache Funktionsprüfung eingefügt, die zurückfällt auf das direkte Ausführen von toggleText() in Browsern, die Element.startViewTransition() nicht unterstützen.

js
btn.addEventListener("click", handleClick);

function toggleText() {
  if (para.className === "1") {
    para.className = "0";
  } else {
    para.className = "1";
  }
  para.textContent = content[Number(para.className)];
}

function handleClick() {
  if (!section.startViewTransition) {
    toggleText();
    return;
  }
  const vt = section.startViewTransition(() => {
    toggleText();
  });
}

Ergebnis

Klicken Sie auf den Button und beachten Sie, wie der Übergang nicht aus dem <section> herausfließt — er bleibt auf den Übergangs-Scopes beschränkt.

Verschachtelte elementspezifische View-Transitions

Ein weiterer Aspekt von elementspezifischen View-Transitions, der erwähnenswert ist, ist, dass Sie View-Transitions verschachteln und sie gleichzeitig ohne Beeinträchtigungen ausführen können. Dies ist möglich, weil, wie bereits erwähnt, der Browser automatisch einen view-transition-scope-Wert von all auf die Scope-Root-Elemente anwendet. Dies stellt sicher, dass view-transition-name-Werte auf den Unterbaum des Elements beschränkt sind und verhindert, dass Elemente und ihre Inhalte von einem äußeren, gleichzeitigen View-Transition erfasst werden. Browser ignorieren Elemente, die view-transition-scope: all haben, während des Snapshot-Prozesses.

Schauen wir uns eine Demonstration von verschachtelten elementspezifischen View-Transitions an.

Das HTML ist das gleiche wie für das erste Beispiel, außer dass es jetzt zwei Listen mit Links innerhalb eines zusätzlichen Wrapper-Elements gibt.

CSS

Die beiden Listen sind innerhalb des .wrapper-Elements nebeneinander mit flexbox angeordnet. Wir geben dem Wrapper ein view-transition-name von wrapper und dann geben wir jeder Liste eine andere Hintergrundfarbe:

css
.wrapper {
  display: flex;
  gap: 20px;
  view-transition-name: wrapper;
}

.one {
  background-color: orange;
}

.two {
  background-color: green;
}

Wir wenden auch unterschiedliche Animationen auf die allgemeinen alten und neuen Übergangspseudo-Elemente an und dann separate Animationen auf die alten und neuen Übergangspseudo-Elemente des wrappers:

css
::view-transition-old(*) {
  animation: rotate-out 0.3s 1 both linear;
}

::view-transition-new(*) {
  animation: rotate-in 0.3s 0.3s 1 both linear;
}

::view-transition-old(wrapper) {
  animation: fade-out 0.3s 1 both linear;
}

::view-transition-new(wrapper) {
  animation: fade-in 0.3s 0.3s 1 both linear;
}

Wir haben den Rest des CSS der Kürze halber verborgen.

JavaScript

Das JavaScript ist dem ersten Beispiel ähnlich, außer dass hier zwei elementspezifische View-Transitions gleichzeitig ausgeführt werden, jedes Mal wenn ein Link angeklickt wird. Der erste wechselt den Text des Links zwischen "Standard" und "Alternative" (über die toggleText()-Funktion) und der zweite tauscht die Position der beiden Listen innerhalb des DOM (über die togglePosition()-Funktion). Wie zuvor haben wir Funktionsprüfcode eingefügt, sodass das Beispiel weiterhin in Browsern funktioniert, die Element.startViewTransition() nicht unterstützen.

js
const lists = document.querySelectorAll("ul");
const wrapper = document.querySelector(".wrapper");

lists.forEach((list) => {
  list.addEventListener("click", handleClick);
});

function handleClick(e) {
  function toggleText() {
    if (e.target.textContent === "Standard") {
      e.target.textContent = "Alternative";
    } else {
      e.target.textContent = "Standard";
    }
  }
  function togglePosition() {
    if (lists[0].nextElementSibling === lists[1]) {
      wrapper.insertBefore(lists[1], lists[0]);
    } else {
      wrapper.insertBefore(lists[0], lists[1]);
    }
  }
  if (e.target.tagName === "A") {
    if (!e.target.startViewTransition) {
      toggleText();
      togglePosition();
      return;
    }

    e.target.startViewTransition(() => {
      toggleText();
    });
    wrapper.startViewTransition(() => {
      togglePosition();
    });
  }
}

Ergebnis

Klicken Sie auf den Text innerhalb eines beliebigen Feldes. Beachten Sie, wie das Umschalten des Textes und das Austauschen der Listen gleichzeitig geschehen - beide verschachtelten Übergänge laufen gleichzeitig ohne Beeinträchtigung.

Abfragen von aktiven View-Transitions

Die folgenden Eigenschaften ermöglichen es Ihnen, aktive elementspezifische View-Transitions abzufragen:

Zum Beispiel, wenn Sie die während eines Übergangs aktiven Animationen auf einem Element in irgendeiner Weise verarbeiten möchten, können Sie auf diese über transitionRoot zugreifen:

js
function processAnimations(transition) {
  const anims = transition.transitionRoot.getAnimations();
  // ...
}

// ...

const transition = el.startViewTransition();
transition.ready.then(() => processAnimations(transition));

Siehe auch