You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
By default, setting `view-transition-name` on multiple elements generates a flat [=view transition tree=], where all the ''::view-transition-group()'' pseudo-elements are children of the ''::view-transition'' pseudo-element.
755
+
This is sufficient for many simple use-cases, but there are some styling use-cases that cannot be achieved with a flat tree.
756
+
The most prominent use-case is clipping: with a flat tree, all pseudo-elements are clipped to the [=snapshot containing block=], so clipping elements in the normal tree would lose their clipping during the view-transition, resulting in a broken visual effect.
757
+
The effects that have can have an unexpected visual effect in a flat tree:
758
+
* Clipping ('overflow', 'clip-path', 'border-radius'): clipping affects the children of the element.
759
+
* 'opacity', 'mask-image' and 'filter': These effects that are designed to work on a fully rasterized image of a tree, rather than on each item individually.
760
+
* 3D transforms ('transform-style', 'transform', 'perspective'): to display the full range of 3D transform animations, some hierarchy needs to be kept.
761
+
762
+
To enable these use cases, this specification introduces the concept of nesting view-transition pseudo-elements. By using the 'view-transition-group' CSS property,
763
+
the author can assign a "parent group" for a generated ''::view-transition-group()'' pseudo-element, creating a hierarchy in the [=view transition tree=].
764
+
765
+
## Examples ## {#nested-vt-example}
766
+
767
+
<div class="example">
768
+
This example creates a transition where the [=view transition tree=] is nested instead of flat:
769
+
770
+
```html
771
+
<section class="container">
772
+
<article>Content</article>
773
+
</section>
774
+
```
775
+
776
+
```css
777
+
.container {
778
+
view-transition-name: container;
779
+
}
780
+
781
+
.container,
782
+
::view-transition-group(container) {
783
+
clip-path: circle();
784
+
}
785
+
786
+
article {
787
+
view-transition-name: article;
788
+
view-transition-group: container;
789
+
}
790
+
```
791
+
792
+
By applying the ''clip-path'' to both the containing element and its generated pseudo-element, we preserve the clip during the transition,
793
+
and by applying ''view-transition-group'' to the internal element referencing the container, we make the tree "nested" in a way that would apply this clipping.
794
+
</main>
795
+
796
+
## The 'view-transition-group' property ## {#view-transition-group-prop}
797
+
798
+
<pre class=propdef>
799
+
Name: view-transition-group
800
+
Value: normal | contain | nearest | <<custom-ident>>
801
+
Initial: normal
802
+
Inherited: no
803
+
Percentages: n/a
804
+
Computed Value: as specified
805
+
Animation type: discrete
806
+
</pre>
807
+
808
+
The 'view-transition-group' property can be used in conjuction with 'view-transition-name' to generate a hierarchy of [=named view transition pseudo-element=].
809
+
810
+
The [=used value=] for 'view-transition-group' resolves to a 'view-transition-name' in its ancestor chain, or to ''view-transition-name/none''. When generating the [=named view transition pseudo-element=], the ''::view-transition-group()'' with that name
811
+
would be the parent of the ''::view-transition-group()'' generated for this element's 'view-transition-name'.
812
+
813
+
When the [=computed value=] of 'view-transition-name' for an element is ''view-transition-name/none'', its 'view-transition-group'[=used value=] is always resolved to ''view-transition-name/none'' as well.
814
+
815
+
<dl dfn-type=value dfn-for=view-transition-group>
816
+
: <dfn>normal</dfn>
817
+
:: The [=used value=] is the element's [=nearest containing group name=].
818
+
819
+
: <dfn>nearest</dfn>
820
+
:: The [=used value=] is the 'view-transition-name'[=computed value=] of the nearest ancestor whose 'view-transition-name'[=computed value=] is not ''view-transition-name/none''.
821
+
822
+
: <dfn>contain</dfn>
823
+
:: The [=used value=] is the element's [=nearest containing group name=].
824
+
825
+
Note: Descendant elements are contained within this group by default, as it would be their element's [=nearest containing group name=].
826
+
827
+
: <dfn><<custom-ident>></dfn>
828
+
:: The [=used value=] is the given <<custom-ident>> if the element has an ancestor whose 'view-transition-name'[=computed value=] is that <<custom-ident>>, otherwise the element's [=nearest containing group name=]
829
+
</dl>
830
+
737
831
# Algorithms # {#algorithms}
738
832
739
833
## Data structures ## {#cross-doc-data-structures}
@@ -780,6 +874,12 @@ The [=captured element=] struct should contain these fields, in addition to the
780
874
<dl>
781
875
: <dfn for="captured element">class list</dfn>
782
876
:: a [=/list=] of strings, initially empty.
877
+
878
+
: <dfn for="captured element">containing group name</dfn>
879
+
:: Null or a string, initially null.
880
+
881
+
: <dfn for="captured element">transform from snapshot containing block</dfn>
882
+
:: A [=matrix=], initially the identity matrix.
783
883
</dl>
784
884
785
885
## Resolving the ''@view-transition'' rule ## {#vt-rule-algo}
@@ -985,6 +1085,67 @@ When capturing the old or new state for an element, perform the following steps
985
1085
Note: This is written in a monkey-patch manner, and will be merged into the algorithm once the L1 spec graduates.
986
1086
</div>
987
1087
1088
+
## Capturing and applying 'view-transition-group' ## {#vt-group-algorithm}
1089
+
1090
+
### Compute the nearest containing 'view-transition-group' ### {#vt-group-nearest-contain}
1091
+
<div algorithm="nearest containing group name">
1092
+
1093
+
To get the <dfn>nearest containing group name</dfn> for an {{Element}} |element|, perform the following steps:
1094
+
1095
+
1. Let |nearestAncestorWithContain| be |element|'s nearest ancestor whose 'view-transition-name' [=computed value=] is not ''view-transition-name/none'' and whose 'view-transition-group'[=computed value=] is ''view-transition-group/contain''.
1096
+
1. If |nearestAncestorWithContain| is null, return ''view-transition-group/none''.
### Compute the old 'view-transition-group' ### {#vt-group-capture-old}
1101
+
<div algorithm="additional old capture steps (group)">
1102
+
When [[css-view-transitions-1#capture-old-state-algorithm|capturing the old state for an element]], perform the following steps given a [=captured element=] |capturedElement|, and an [=element=] |element|:
1103
+
1104
+
1. Set |capturedElement|'s [=captured element/containing group name=] to the [=used value=] of |element|'s ''view-transition-group''.
1105
+
</div>
1106
+
1107
+
### Compute the new 'view-transition-group' ### {#vt-group-capture-new}
1108
+
<div algorithm="additional new capture steps (group)">
1109
+
When [[css-view-transitions-1#capture-new-state-algorithm|capturing the new state for an element]], perform the following steps given a [=captured element=] |capturedElement| and an [=element=] |element|:
1110
+
1111
+
1. Set |capturedElement|'s [=captured element/containing group name=] to the [=used value=] of |element|'s 'view-transition-group'.
1112
+
</div>
1113
+
1114
+
### Reparent a ''::view-transition-group()'' to its specified containing group ### {#vt-group-reparent}
When [[css-view-transitions-1#setup-transition-pseudo-elements-algorithm|setting up the transition pseudo-element]] for a [=captured element=] |capturedElement|, given a |transitionName| and a |transition|:
1117
+
1118
+
1. Let |containingGroupName| be |capturedElement|'s [=containing group name=].
1119
+
1. If |containingGroupName| is not null, then:
1120
+
1121
+
1. Let |groupContainerElement| be |transition|'s [=ViewTransition/named elements=][|containingGroupName|].
1122
+
1123
+
1. Let |group| be the ''::view-transition-group()'',
1124
+
whose [=view transition name=] is set to |transitionName|.
1125
+
1126
+
1. Let |parentGroup| be the ''::view-transition-group()'',
1127
+
whose [=view transition name=] is set to |containingGroupName|.
1128
+
1129
+
1. Append |group| to |parentGroup|.
1130
+
1131
+
1. When setting the animation keyframes given |transform|, [=multiply=] |transform| by the inverse matrix of |groupContainerElement|'s [=old transform=].
1132
+
1133
+
Note: It is TBD how this is resolved when the old and new groups mismatch. See <a href="https://github.com/w3c/csswg-drafts/issues/10631">Issue 10631</a>.
1134
+
</div>
1135
+
1136
+
### Adjust the group's 'transform' to be relative to its containing ''::view-transition-group()'' ### {#vt-group-transform-adjust}
When [[css-view-transitions-1#style-transition-pseudo-elements-algorithm|updating the style of the transition pseudo-element]], perform the following steps before setting the [=captured element/group styles rule=], given a [=captured element=] |capturedElement|, given a |transform| and a {{ViewTransition}} |transition|:
1139
+
1140
+
1. Set |capturedElement|'s [=transform from snapshot containing block=] to |transform|.
1141
+
1142
+
1. If |capturedElement|'s [=containing group name=] is not null, then:
1143
+
1144
+
1. Let |groupContainerElement| be |transition|'s [=ViewTransition/named elements=][|capturedElement|'s [=containing group name=]].
1145
+
1146
+
1. [=Multiply=] |transform| by the inverse matrix of |groupContainerElement|'s [=transform from snapshot containing block=].
0 commit comments