- From: Bramus via GitHub <noreply@w3.org>
- Date: Wed, 10 Dec 2025 08:50:45 +0000
- To: public-css-archive@w3.org
> 3. Extend the semantics of `view-transition-group` so that `contain` generates a `::view-transition-group-children()` pseudo even if the element has `view-transition-name: none` and is therefore not itself a participant in the transition.
>
> […]
>
> The developer still has the option to create a scope that is not self-participating, by setting `view-transition-name: none`. Such a scope would generate a `::v-t-group-children` but not a `::v-t-group` or a `::v-t-old` or a `::v-t-new`.
>
> The developer can also, if they want, set `view-transition-group: none` on the scope, to suppress the `::v-t-group-children` and override the default nesting behavior in our proposal.
We discussed this a bit more internally and I pointed out that this has some weird side-effects on the pseudo-tree that needs to be generated. Specifically, if the scope has no `view-transition-name`, then:
- What would go inside of the parenthesis of `::view-transition-group-children()`?
- Where does this `::view-transition-group-children()` pseudo get placed in the tree? Directly under the `::view-transition` instead of under its `::view-transition-group()`?
I mean, this seems weird:
```
#element
└─ ::view-transition
└─::view-transition-group-children(⁉️)
├─ ::view-transition-group(child1)
│ └─ ::view-transition-image-pair(child1)
│ ├─ ::view-transition-old(child1)
│ └─ ::view-transition-new(child1)
└─ ::view-transition-group(child2)
└─ ::view-transition-image-pair(child2)
├─ ::view-transition-old(child2)
└─ ::view-transition-new(child2)
```
---
A solution that doesn’t have this side-effect is to **always** capture the scope as part of a scoped view transition _(thus: the scope is always self-participating)_, but give authors a way to indicate that they only want to capture its dimensions – so without its pixels/textures.
When only capturing the dimensions, this results in a more consistent pseudo-tree:
- The `::view-transition-group(root)` for that element is always generated
- There is a `::view-transition-group-children(root)` for its children that were captured (if any)
- The `::view-transition-image-pair` becomes conditional, without affecting the rest.
In practice, the pseudo-tree would look like this:
- When capturing dimensions + texture (default behavior):
```
#element
└─ ::view-transition
└─ ::view-transition-group(root)
├─ ::view-transition-image-pair(root)
│ ├─ ::view-transition-old(root)
│ └─ ::view-transition-new(root)
└─::view-transition-group-children(root)
├─ ::view-transition-group(child1)
│ └─ ::view-transition-image-pair(child1)
│ ├─ ::view-transition-old(child1)
│ └─ ::view-transition-new(child1)
└─ ::view-transition-group(child2)
└─ ::view-transition-image-pair(child2)
├─ ::view-transition-old(child2)
└─ ::view-transition-new(child2)
```
- When capturing only the dimensions:
```
#element
└─ ::view-transition
└─ ::view-transition-group(root)
└─::view-transition-group-children(root)
├─ ::view-transition-group(child1)
│ └─ ::view-transition-image-pair(child1)
│ ├─ ::view-transition-old(child1)
│ └─ ::view-transition-new(child1)
└─ ::view-transition-group(child2)
└─ ::view-transition-image-pair(child2)
├─ ::view-transition-old(child2)
└─ ::view-transition-new(child2)
```
Additionally, when only capturing the dimensions, the real (new) element still gets drawn underneath the scoped transition pseudo-tree.
---
There is still an open question on how authors can do this opt-in.
Some options we discussed:
1. Give authors a CSS property to indicate this behavior.
```css
#element {
view-transition-capture-mode: dimensions; /* initial value: normal */
}
```
I believe this `view-transition-capture-mode: dimensions` would also prove itself useful for other parts of View Transitions (not linked to scoped transitions) such as in-place element transitions, making https://www.bram.us/2025/05/15/view-transitions-border-radius-revisited/#a-simpler-approach more easier for authors to do.
Note that for this to work, the UA would generate this stylesheet whenever you start a Scoped View Transition:
```css
vt-scope {
view-transition-name: root !important;
view-transition-group: contain;
}
/* Conditional. Only gets set if the scope’s overflow style is not visible */
vt-scope::view-transition-group-children(root) {
overflow: clip;
}
```
The `!important` might catch your eye there, but I think this is warranted here because you always want the scope to be captured.
The effect on Steve’s proposal would be that bullet 3 in the list becomes this:
> 3. User-agent style sets `view-transition-group: root !important` on the scope during its transition. Authors can opt-out from capturing the pixels of the scope by declaring `view-transition-capture-mode: dimensions;` on it.
2. The same as 1, but do the opt-in from JS
```js
document.querySelector('#element').startViewTransition({
callback: () => { … },
rootCapture: "dimensions-only",
);
```
This feels pretty limited, as it’s a flag that only works for Scoped Transitions.
3. Automagically do this when authors set `view-transition-name: none` on the scope root in their author stylesheet.
Personally I find this a bit too magical, because authors are indicating that they don’t want to capture it, yet somehow it would still show up in the pseudo-tree.
4. _[insert-your-idea-here]_
--
GitHub Notification of comment by bramus
Please view or discuss this issue at https://github.com/w3c/csswg-drafts/issues/12324#issuecomment-3636012365 using your GitHub account
--
Sent via github-notify-ml as configured in https://github.com/w3c/github-notify-ml-config
Received on Wednesday, 10 December 2025 08:50:46 UTC