Publié le 22 septembre 2025
Lorsque vous démarrez une transition de vue, le navigateur prend automatiquement des instantanés avant et après des éléments tagués avec un view-transition-name. Ces instantanés sont affichés dans une arborescence de pseudo-éléments. Par défaut, l'arborescence générée est "plate". Cela signifie que la hiérarchie d'origine dans le DOM est perdue et que tous les groupes de transition de vue capturés sont des frères et sœurs sous un seul pseudo-élément ::view-transition.
Cette approche d'arborescence plate est suffisante pour de nombreux cas d'utilisation, mais certains cas d'utilisation de style ne peuvent pas être réalisés avec cette approche. Voici des exemples d'effets pouvant avoir un effet visuel inattendu dans une arborescence plate :
- Découpage (
overflow,clip-path,border-radius) : le découpage affecte les enfants de l'élément, ce qui signifie que les éléments frères du groupe de transition de vue ne peuvent pas se découper les uns les autres. opacity,mask-imageetfilter: de même, ces effets sont conçus pour fonctionner sur une image entièrement pixélisée d'une arborescence, en affectant les enfants plutôt que chaque élément individuellement.- Transformations 3D (
transform-style,transform,perspective) : pour afficher l'ensemble des animations de transformation 3D, une certaine hiérarchie doit être conservée.
L'exemple suivant montre un pseudo-arbre plat, avec des éléments qui sont coupés par un ancêtre dans l'arbre DOM. Ces éléments perdent leur découpage pendant la transition de vue, ce qui entraîne un effet visuel défectueux.
Les groupes de transition de vue imbriqués sont une extension des transitions de vue qui vous permet d'imbriquer des pseudo-éléments ::view-transition-group les uns dans les autres. Lorsque les groupes de transition de vue sont imbriqués, il est possible de restaurer des effets tels que le rognage pendant la transition.
Browser Support
D'un pseudo-arbre plat à un pseudo-arbre imbriqué
Dans la démonstration suivante, vous pouvez cliquer sur l'avatar d'une personne pour afficher plus d'informations la concernant. Les animations sont gérées par une transition de vue du même document qui transforme le bouton cliqué en boîte de dialogue, déplace l'avatar et le nom sur l'écran, et fait glisser les paragraphes de la boîte de dialogue vers le haut ou vers le bas.
Démonstration en direct
Enregistrement de la démonstration
Enregistrement de la démonstration (ralenti)
Si vous regardez de plus près la démonstration, vous constaterez qu'il y a un problème avec la transition : même si les paragraphes contenant la description sont des enfants de l'élément <dialog> dans le DOM, le texte n'est pas tronqué par la zone <dialog> pendant la transition :
<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>
L'application de overflow: clip sur <dialog> n'a pas non plus d'effet.
Le problème réside dans la façon dont les transitions de vue créent et affichent leur pseudo-arborescence :
- Dans le pseudo-arbre, par défaut, tous les instantanés sont frères les uns des autres.
- Le pseudo-arbre est affiché dans un pseudo-élément
::view-transitionqui s'affiche au-dessus de l'ensemble du document.
Pour cette démonstration, l'arborescence DOM se présente comme suit :
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
└─ …
Comme les pseudo-éléments ::view-transition-group(.text) sont des frères et sœurs du pseudo-élément ::view-transition-group(card), ils sont peints au-dessus de la carte.
Pour que ::view-transition-group(card) coupe ::view-transition-group(.text), les pseudo-éléments ::view-transition-group(.text) doivent être des enfants de ::view-transition-group(card). Pour ce faire, utilisez view-transition-group, qui vous permet d'attribuer un "groupe parent" à un pseudo-élément ::view-transition-group() généré.
Pour modifier le groupe parent, deux options s'offrent à vous :
- Sur le parent, définissez
view-transition-groupsurcontainpour qu'il contienne tous les enfants avec unview-transition-name. - Sur tous les enfants, définissez
view-transition-groupsur l'view-transition-namedu parent. Vous pouvez également utilisernearestpour cibler le groupe ancêtre le plus proche.
Pour cette démonstration, afin d'utiliser des groupes de transitions de vue imbriqués, le code devient :
button.clicked,
dialog {
view-transition-group: contain;
}
Ou
button.clicked,
dialog *,
view-transition-group: nearest;
}
Avec ce code, les pseudo-classes ::view-transition-group(.text) sont désormais imbriquées dans la pseudo-classe ::view-transition-group(card). Pour ce faire, un pseudo ::view-transition-group-children(…) supplémentaire est utilisé, ce qui permet de regrouper tous les pseudos imbriqués :
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
└─ …
Enfin, pour que le pseudo ::view-transition-group(card) tronque les paragraphes, appliquez overflow: clip au pseudo ::view-transition-group-children(card) :
::view-transition-group-children(card) {
overflow: clip;
}
Le résultat est le suivant :
Démonstration en direct
Enregistrement de la démonstration
Enregistrement de la démonstration (ralenti)
Le pseudo ::view-transition-group-children n'est présent que lorsque des groupes imbriqués sont utilisés. Il est dimensionné en fonction de la boîte de bordure de l'élément d'origine et reçoit une bordure transparente de la même forme et de la même épaisseur que l'élément qui a généré le pseudo-élément (card dans l'exemple précédent).
Découpage et plus
Les groupes de transitions de vue imbriqués sont utilisés ailleurs que pour les effets de rognage. Les effets 3D en sont un autre exemple. Dans la démonstration suivante, une option permet de faire pivoter la carte en 3D pendant la transition.
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;
}
}
Sans groupes de transitions de vue imbriqués, l'avatar et le nom ne pivotent pas avec la carte.
Démonstration en direct
Enregistrement de la démonstration
Enregistrement de la démonstration (ralenti)
En imbriquant les pseudos de l'avatar et du nom dans la fiche, l'effet 3D peut être restauré. Mais ce n'est pas tout. En plus de faire tourner les pseudos ::view-transition-old(card) et ::view-transition-new(card), vous devez également faire tourner le pseudo ::view-transition-group-children(card).
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;
}
}
Démonstration en direct
Enregistrement de la démonstration
Enregistrement de la démonstration (ralenti)
Autres démos
Dans l'exemple suivant, des groupes de transitions de vue imbriqués sont utilisés pour s'assurer que les fiches sont découpées par leur défilement parent. Vous pouvez activer ou désactiver l'utilisation de groupes de transitions de vues imbriqués à l'aide des commandes incluses.
Démonstration en direct
Enregistrement de la démonstration
Ce qui est intéressant avec cette démonstration, c'est que tous les pseudo-éléments ::view-transition-group(.card) sont imbriqués dans le pseudo-élément ancêtre ::view-transition-group(cards) et découpés par celui-ci. Le #targeted-card est exclu, car son animation d'entrée/sortie ne doit pas être coupée par le ::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;
}
Récapitulatif
Les transitions de vue imbriquées vous permettent de conserver une partie de la topologie de l'arborescence DOM lors de la construction des pseudo-éléments. Cela permet d'obtenir divers effets qui n'étaient pas possibles auparavant avec les transitions de vue, dont certains sont décrits ici.
L'imbrication modifie le modèle de construction des transitions de vue et est destinée à être utilisée pour créer des effets avancés. Comme indiqué, les transitions de vue limitées à un élément peuvent également accomplir un sous-ensemble des effets avec un modèle plus simple. Nous vous encourageons à essayer les deux fonctionnalités pour déterminer celle qui correspond le mieux à vos besoins.