Clipping-Probleme (und mehr) bei Ansichtsübergängen mit verschachtelten Ansichtsübergangsgruppen verhindern

Veröffentlicht: 22. September 2025

Wenn Sie einen Ansichtsübergang starten, erstellt der Browser automatisch Vorher- und Nachher-Snapshots von Elementen, die mit einem view-transition-name getaggt sind. Diese Snapshots werden in einer Baumstruktur aus Pseudoelementen gerendert. Standardmäßig ist der generierte Baum „flach“. Das bedeutet, dass die ursprüngliche Hierarchie im DOM verloren geht und alle erfassten Ansichtsübergangsgruppen gleichrangige Elemente unter einem einzigen ::view-transition-Pseudoelement sind.

Dieser Ansatz mit flacher Baumstruktur ist für viele Anwendungsfälle ausreichend, aber es gibt einige Styling-Anwendungsfälle, die damit nicht umgesetzt werden können. Im Folgenden finden Sie Beispiele für Effekte, die in einem flachen Baum zu unerwarteten visuellen Effekten führen können:

  • Clipping (overflow, clip-path, border-radius): Das Clipping wirkt sich auf die untergeordneten Elemente des Elements aus. Das bedeutet, dass sich gleichgeordnete Elemente der Ansichtsübergangsgruppe nicht gegenseitig clippen können.
  • opacity, mask-image und filter: Diese Effekte sind so konzipiert, dass sie auf ein vollständig gerastertes Bild eines Baums angewendet werden und sich auf die untergeordneten Elemente auswirken, anstatt auf jedes Element einzeln.
  • 3D-Transformationen (transform-style, transform, perspective): Damit alle 3D-Transformationsanimationen angezeigt werden, muss eine bestimmte Hierarchie beibehalten werden.

Das folgende Beispiel zeigt einen flachen Pseudobaum mit Elementen, die von einem Ancestor im DOM-Baum abgeschnitten werden. Diese Elemente verlieren während des Ansichtsübergangs ihre Beschneidung, was zu einem fehlerhaften visuellen Effekt führt.

Aufzeichnung eines fehlerhaften Clipping-Effekts während eines Ansichtsübergangs. Der Text sollte durch das Dialogfeld abgeschnitten werden, wird es aber nicht. Die Animation wird verlangsamt, um den Effekt zu verdeutlichen.

Verschachtelte Ansichtsübergangsgruppen sind eine Erweiterung für Ansichtsübergänge, mit der Sie ::view-transition-group-Pseudoelemente ineinander verschachteln können. Wenn Ansichtsübergangsgruppen verschachtelt sind, können Effekte wie das Zuschneiden während des Übergangs wiederhergestellt werden.

Browser Support

  • Chrome: 140.
  • Edge: 140.
  • Firefox: not supported.
  • Safari: not supported.

Von einem flachen Pseudobaum zu einem verschachtelten Pseudobaum

In der folgenden Demo können Sie auf den Avatar einer Person klicken, um weitere Informationen zu dieser Person zu sehen. Die Animationen werden durch einen Ansichtsübergang im selben Dokument verarbeitet, der die angeklickte Schaltfläche in das Dialogfeld umwandelt, den Avatar und den Namen über den Bildschirm bewegt und die Absätze aus dem Dialogfeld nach oben oder unten verschiebt.

Live-Demo

Demoaufnahme

Demoaufnahme (langsamere Version)

Wenn Sie sich die Demo genau ansehen, werden Sie feststellen, dass es ein Problem mit dem Übergang gibt: Obwohl die Absätze mit der Beschreibung im DOM untergeordnete Elemente des <dialog>-Elements sind, wird der Text während des Übergangs nicht durch die Box des <dialog>-Elements abgeschnitten:

<dialog id="info_bramus" closedby="any">
  <h2><img alt="…" class="avatar" height="96" width="96" src="avatar_bramus.jpg"> <span>Bramus</span></h2>
  <p>Bramus is …</p>
  <p>…</p>
</dialog>

Das Anwenden von overflow: clip auf <dialog> hat ebenfalls keine Auswirkungen.

Das Problem liegt darin, wie Ansichtsübergänge ihren Pseudobaum erstellen und rendern:

  • Im Pseudobaum sind standardmäßig alle Snapshots gleichrangig.
  • Der Pseudobaum wird in einem ::view-transition-Pseudoelement gerendert, das über dem gesamten Dokument gerendert wird.

Für diese Demo sieht der DOM-Baum so aus:

html
  ├─ ::view-transition
  │  ├─ ::view-transition-group(card)
  │  │  └─ ::view-transition-image-pair(card)
  │  │     ├─ ::view-transition-old(card)
  │  │     └─ ::view-transition-new(card)
  │  ├─ ::view-transition-group(name)
  │  │  └─ ::view-transition-image-pair(name)
  │  │     ├─ ::view-transition-old(name)
  │  │     └─ ::view-transition-new(name)
  │  ├─ ::view-transition-group(avatar)
  │  │  └─ ::view-transition-image-pair(avatar)
  │  │     ├─ ::view-transition-old(avatar)
  │  │     └─ ::view-transition-new(avatar)
  │  ├─ ::view-transition-group(paragraph1.text)
  │  │  └─ ::view-transition-image-pair(paragraph1.text)
  │  │     └─ ::view-transition-new(paragraph1.text)
  │  └─ ::view-transition-group(paragraph2.text)
  │     └─ ::view-transition-image-pair(paragraph2.text)
  │        └─ ::view-transition-new(paragraph2.text)
  ├─ head
  └─ body
        └─ …

Da die ::view-transition-group(.text)-Pseudoelemente nachfolgende Geschwister des ::view-transition-group(card)-Pseudoelements sind, werden sie über der Karte dargestellt.

Damit ::view-transition-group(card) ::view-transition-group(.text) abschneidet, müssen die ::view-transition-group(.text)-Pseudoelemente untergeordnete Elemente von ::view-transition-group(card) sein. Verwenden Sie dazu view-transition-group, um einem generierten ::view-transition-group()-Pseudoelement eine „übergeordnete Gruppe“ zuzuweisen.

Sie haben zwei Möglichkeiten, die übergeordnete Gruppe zu ändern:

  • Legen Sie für das übergeordnete Element view-transition-group auf contain fest, damit es alle untergeordneten Elemente mit view-transition-name enthält.
  • Legen Sie für alle untergeordneten Elemente die view-transition-group auf die view-transition-name des übergeordneten Elements fest. Sie können auch nearest verwenden, um die nächstgelegene übergeordnete Gruppe anzusprechen.

Für diese Demo sieht der Code für verschachtelte Ansichtsübergangsgruppen so aus:

button.clicked,
dialog {
  view-transition-group: contain;
}

Oder

button.clicked,
dialog *,
  view-transition-group: nearest;
}

Mit diesem Code werden die ::view-transition-group(.text)-Pseudoelemente jetzt im ::view-transition-group(card)-Pseudoelement verschachtelt. Dies geschieht in einem zusätzlichen ::view-transition-group-children(…)-Pseudoelement, das alle verschachtelten Pseudoelemente zusammenhält:

html
  ├─ ::view-transition
  │  ├─ ::view-transition-group(card)
  │  │  ├─::view-transition-group-children(card)
  │  │  │ ├─ ::view-transition-group(paragraph1.text)
  │  │  │ │  └─ ::view-transition-image-pair(paragraph1.text)
  │  │  │ │     └─ ::view-transition-new(paragraph1.text)
  │  │  │ └─ ::view-transition-group(paragraph2.text)
  │  │  │    └─ ::view-transition-image-pair(paragraph2.text)
  │  │  │       └─ ::view-transition-new(paragraph2.text)
  │  │  └─ ::view-transition-image-pair(card)
  │  │     ├─ ::view-transition-old(card)
  │  │     └─ ::view-transition-new(card)
  │  ├─ ::view-transition-group(name)
  │  │  └─ ::view-transition-image-pair(name)
  │  │     ├─ ::view-transition-old(name)
  │  │     └─ ::view-transition-new(name)
  │  └─ ::view-transition-group(avatar)
  │     └─ ::view-transition-image-pair(avatar)
  │        ├─ ::view-transition-old(avatar)
  │        └─ ::view-transition-new(avatar)
  ├─ head
  └─ body
        └─ …

Damit das Pseudoelement ::view-transition-group(card) die Absätze abschneidet, wenden Sie overflow: clip auf das Pseudoelement ::view-transition-group-children(card) an:

::view-transition-group-children(card) {
  overflow: clip;
}

Das Ergebnis lautet:

Live-Demo

Demoaufnahme

Demoaufnahme (verlangsamt)

Das Pseudoelement ::view-transition-group-children ist nur vorhanden, wenn verschachtelte Gruppen verwendet werden. Es wird auf die Größe der Rahmenbox des ursprünglichen Elements angepasst und erhält einen transparenten Rahmen mit derselben Form und Rahmenstärke wie das Element, das das Pseudoelement generiert hat – card im vorherigen Beispiel.

Clipping und mehr

Verschachtelte Ansichtsübergangsgruppen werden nicht nur für Clipping-Effekte verwendet. Ein weiteres Beispiel sind 3D-Effekte. In der folgenden Demo gibt es eine Option, mit der die Karte während des Übergangs in 3D gedreht werden kann.

html:active-view-transition-type(open) {
    &::view-transition-old(card) {
        animation-name: rotate-out;
    }
    &::view-transition-new(card) {
        animation-name: rotate-in;
    }
}
html:active-view-transition-type(close) {
    &::view-transition-old(card) {
        animation-name: rotate-in;
    }
    &::view-transition-new(card) {
        animation-name: rotate-out;
    }
}

Ohne verschachtelte Ansichtsübergangsgruppen drehen sich der Avatar und der Name nicht mit der Karte.

Live-Demo

Demoaufnahme

Demoaufnahme (langsamere Version)

Wenn Sie die Pseudoelemente für Avatar und Name in der Karte verschachteln, kann der 3D-Effekt wiederhergestellt werden. Das ist aber nicht das Einzige, was Sie tun müssen. Neben der Rotation der Pseudoklassen ::view-transition-old(card) und ::view-transition-new(card) müssen Sie auch die Pseudoklasse ::view-transition-group-children(card) rotieren.

html:active-view-transition-type(open) {
    &::view-transition-group-children(card) {
        animation: rotate-in var(--duration) ease;
        backface-visibility: hidden;
    }
}
html:active-view-transition-type(close) {
    &::view-transition-group-children(card) {
        animation: rotate-out var(--duration) ease;
        backface-visibility: hidden;
    }
}

Live-Demo

Demoaufnahme

Demoaufnahme (langsamere Version)

Weitere Demos

Im folgenden Beispiel werden verschachtelte Ansichtsübergangsgruppen verwendet, um dafür zu sorgen, dass die Karten von ihrem übergeordneten Scroller abgeschnitten werden. Mit den enthaltenen Steuerelementen können Sie die Verwendung verschachtelter Ansichtsübergangsgruppen aktivieren oder deaktivieren.

Live-Demo

Demoaufnahme

Das Interessante an dieser Demo ist, dass alle ::view-transition-group(.card)-Pseudoelemente im übergeordneten ::view-transition-group(cards)-Pseudoelement verschachtelt und von diesem abgeschnitten werden. Die #targeted-card-Animation ist ausgeschlossen, da ihre Ein-/Ausstiegsanimation nicht von der ::view-transition-group(cards)-Animation abgeschnitten werden soll.

/* The .cards wrapper contains all children */
.cards {
  view-transition-name: cards;
  view-transition-group: contain;
}

/* Contents that bleed out get clipped */
&::view-transition-group-children(cards) {
  overflow: clip;
}

/* Each card is given a v-t-name and v-t-class */
.card {
  view-transition-name: match-element;
  view-transition-class: card;
}

/* The targeted card is given a unique name (to style the pseudo differently)
   and shouldn't be contained by the ::view-transition-group-children(cards) pseudo */
#targeted-card {
  view-transition-name: targeted-card;
  view-transition-group: none;
}

Zusammenfassung

Mit verschachtelten Ansichtsübergängen können Sie beim Erstellen der Pseudoelemente einen Teil der Topologie des DOM-Baums beibehalten. Dadurch werden verschiedene Effekte möglich, die bisher mit Ansichtsübergängen nicht möglich waren. Einige davon haben wir hier beschrieben.

Durch die Verschachtelung ändert sich das Modell, wie Ansichtsübergänge erstellt werden. Sie ist für die Erstellung erweiterter Effekte gedacht. Wie bereits erwähnt, können mit elementbezogenen Ansichtsübergängen auch einige der Effekte mit einem einfacheren Modell erzielt werden. Wir empfehlen Ihnen, beide Funktionen auszuprobieren, um herauszufinden, welche am besten zu Ihren Anforderungen passt.