Voorkom problemen met afkappen (en meer) in weergaveovergangen door geneste weergaveovergangsgroepen te gebruiken

Gepubliceerd: 22 september 2025

Als je een weergaveovergang start, maakt de browser automatisch momentopnamen van voor en na van elementen die zijn getagd met een view-transition-name. Deze momentopnamen worden gerenderd in een boom van pseudo-elementen. De gegenereerde structuur is standaard plat. Dit betekent dat de oorspronkelijke hiërarchie in de DOM verloren gaat en dat alle vastgelegde weergaveovergangsgroepen siblings zijn onder één ::view-transition pseudo-element.

Deze platte boomstructuur is voldoende voor veel toepassingen, maar er zijn enkele stylingtoepassingen die hiermee niet kunnen worden bereikt. Hieronder staan voorbeelden van effecten die een onverwacht visueel effect kunnen hebben in een platte structuur:

  • Bijsnijden (overflow, clip-path, border-radius): Bijsnijden heeft invloed op de onderliggende elementen van het element. Dit betekent dat de onderliggende elementen van de weergaveovergangsgroep elkaar niet kunnen bijsnijden.
  • opacity, mask-image en filter: deze effecten zijn ook ontworpen om te werken op een volledig gerasterde afbeelding van een boom, waarbij de onderliggende elementen worden beïnvloed in plaats van elk item afzonderlijk.
  • 3D-transformaties (transform-style, transform, perspective): Als u het volledige bereik van 3D-transformatieanimaties wilt tonen, moet u een bepaalde hiërarchie aanhouden.

In het volgende voorbeeld zie je een platte pseudoboom met elementen die worden afgekapt door een bovenliggend element in de DOM-boomstructuur. Deze elementen verliezen hun clipping tijdens de weergaveovergang, wat leidt tot een verbroken visueel effect.

Opname van een onjuist knipeffect tijdens een weergaveovergang. De tekst moet worden afgekapt door het dialoogvenster, maar dat gebeurt niet. De animatietijd is vertraagd om het effect te overdrijven.

Geneste weergaveovergangsgroepen is een extensie voor weergaveovergangen waarmee je ::view-transition-group-pseudoelementen in elkaar kunt nesten. Als weergaveovergangsgroepen zijn genest, is het mogelijk om effecten zoals bijsnijden te herstellen tijdens de overgang.

Browser Support

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

Van een platte pseudoboom naar een geneste pseudoboom

In de volgende demo kun je op de avatar van een persoon klikken om meer informatie over die persoon te bekijken. De animaties worden afgehandeld door een weergaveovergang van hetzelfde document die de aangeklikte knop in het dialoogvenster verandert, de avatar en naam over het scherm verplaatst en de alinea's uit het dialoogvenster omhoog of omlaag schuift.

Live demo

Demo-opname

Demo-opname (vertraagd)

Als je goed naar de demo kijkt, zie je dat er een probleem is met de overgang: hoewel de alinea's met de beschrijving onderliggende elementen zijn van het element <dialog> in de DOM, wordt de tekst tijdens de overgang niet afgekapt door het vak van de <dialog>:

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

Het toepassen van overflow: clip op de <dialog> doet ook niets.

Het probleem is de manier waarop weergaveovergangen hun pseudoboom bouwen en weergeven:

  • In de pseudoboomstructuur zijn alle momentopnamen standaard broers en zussen van elkaar.
  • De pseudostructuur wordt gerenderd in een pseudoelement ::view-transition dat boven op het hele document wordt gerenderd.

Voor deze demo ziet de DOM-boomstructuur er zo uit:

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
        └─ …

Omdat de ::view-transition-group(.text)-pseudoklassen de opvolgende elementen zijn van de ::view-transition-group(card)-pseudoklasse, worden ze boven op de kaart getekend.

Als je wilt dat ::view-transition-group(card) ::view-transition-group(.text) afkapt, moeten de ::view-transition-group(.text)-pseudoklassen onderliggende elementen van ::view-transition-group(card) zijn. Gebruik hiervoor view-transition-group, waarmee je een bovenliggende groep kunt toewijzen voor een gegenereerd pseudo-element ::view-transition-group().

Je kunt de bovenliggende groep op 2 manieren wijzigen:

  • Stel op het bovenliggende element de view-transition-group in op contain, zodat deze alle onderliggende elementen met een view-transition-name bevat.
  • Stel voor alle onderliggende elementen de view-transition-group in op de view-transition-name van het bovenliggende element. U kunt ook nearest gebruiken om de dichtstbijzijnde bovenliggende groep te targeten.

Voor deze demo wordt de code om geneste weergaveovergangsgroepen te gebruiken:

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

of

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

Met deze code worden de ::view-transition-group(.text)-pseudoklassen nu genest in de ::view-transition-group(card)-pseudoklasse. Dit wordt gedaan in een extra ::view-transition-group-children(…)-pseudo, die alle geneste pseudo's bij elkaar houdt:

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
        └─ …

Pas tot slot overflow: clip toe op de ::view-transition-group-children(card)-pseudo om de ::view-transition-group(card)-pseudo de alinea's te laten inkorten:

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

Het resultaat is het volgende:

Live demo

Demo-opname

Demo-opname (vertraagd)

De pseudo ::view-transition-group-children is alleen aanwezig als er geneste groepen worden gebruikt. Het heeft de grootte van het randvak van het oorspronkelijke element en krijgt een transparante rand met dezelfde vorm en randdikte als het element dat het pseudo-element heeft gegenereerd: card in het vorige voorbeeld.

Clippen en meer

Geneste groepen voor weergaveovergangen worden op andere plaatsen gebruikt dan bijvuleffecten. Een ander voorbeeld zijn 3D-effecten. In de volgende demo is er een optie om de kaart tijdens de overgang in 3D te draaien.

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

Zonder geneste weergaveovergangsgroepen draaien de avatar en naam niet mee met de kaart.

Live demo

Demo-opname

Demo-opname (vertraagd)

Door de pseudo-elementen voor de avatar en de naam in de kaart te nesten, kan het 3D-effect worden hersteld. Maar dat is niet het enige wat je moet doen. Naast de pseudo's ::view-transition-old(card) en ::view-transition-new(card) moet je ook de pseudo ::view-transition-group-children(card) roteren.

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

Demo-opname

Demo-opname (vertraagd)

Meer demo's

In het volgende voorbeeld worden geneste weergaveovergangsgroepen gebruikt om te zorgen dat de kaarten worden afgekapt door de bovenliggende scroller. Je kunt het gebruik van geneste weergaveovergangsgroepen aan- of uitzetten met de meegeleverde bedieningselementen.

Live demo

Demo-opname

Het interessante aan deze demo is dat alle ::view-transition-group(.card)-pseudoklassen worden genest in de bovenliggende ::view-transition-group(cards)-pseudoklasse en hierdoor worden afgekapt. De #targeted-card is uitgesloten omdat de animatie voor binnenkomen/verlaten niet mag worden afgekapt door de ::view-transition-group(cards).

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

Samenvatting

Met geneste weergaveovergangen kun je een deel van de topologie van de DOM-boomstructuur behouden als je de pseudo-elementen maakt. Dit maakt verschillende effecten mogelijk die eerder niet mogelijk waren met weergaveovergangen, waarvan we er hier enkele hebben beschreven.

Nesting verandert het model van hoe weergaveovergangen worden opgebouwd en is bedoeld om geavanceerde effecten te maken. Zoals opgemerkt, kunnen weergaveovergangen met elementbereik ook een subset van de effecten bereiken met een eenvoudiger model. We raden je aan beide functies uit te proberen om te bepalen welke het beste bij je behoeften past.