Re: [csswg-drafts] [css-view-transitions-2] [scoped] What is the layout of the ::v-t pseudo in relation to the scope? (#12324)

The CSS Working Group just discussed `[css-view-transitions-2] [scoped] What is the layout of the ::v-t pseudo in relation to the scope?`, and agreed to the following:

* `RESOLVED: make the VT have a stacking context that's a sibling of the scope stacking context, but painted at a point before transforms/filters. Still a child of the scope.`

<details><summary>The full IRC log of that discussion</summary>
&lt;TabAtkins> vmpstr: in scoped VT, reminder it's about VT running on subtrees, not just the document<br>
&lt;TabAtkins> vmpstr: setup is roughly the same, you just start the transition on an element, discover names in the subtree, create VT pseudos representing the transitioning parts of the subtree<br>
&lt;TabAtkins> vmpstr: for document VT we hoist the VT pseudos to the top layer so it can capture the document itself, too, and represent that in its pseudos<br>
&lt;TabAtkins> vmpstr: so we need an equivalent thing for elements. pseudos should be able to capture the hosting element's decorations/background/etc. can't be a child without it being circular<br>
&lt;JakeA> q+<br>
&lt;TabAtkins> vmpstr: so our idea is to have ::v-t pseudo-element be a next-sibling of the VT scope element<br>
&lt;TabAtkins> vmpstr: and then use anchor positioning to put it over top of the scope<br>
&lt;TabAtkins> vmpstr: this works pretty well for a lot of cases<br>
&lt;TabAtkins> vmpstr: one case where it doesn't<br>
&lt;TabAtkins> vmpstr: if the scope element is rotated or not axis aligned<br>
&lt;ntim> q+<br>
&lt;TabAtkins> vmpstr: anchor spec says the anchor box is the axis-aligned bounding box of the anchor<br>
&lt;JakeA> q-<br>
&lt;TabAtkins> vmpstr: there's a workaround, selfishly hoping the anchor spec can eventually allow positioned elements to be in the same positioned space as the anchor<br>
&lt;emilio> q+<br>
&lt;TabAtkins> vmpstr: so we'd like to go ahead with the current design of it being the next sibling, and just positioning it over<br>
&lt;astearns> ack ntim<br>
&lt;TabAtkins> ntim: from an impl pov, a bit worried about making the pseudo a sibling<br>
&lt;TabAtkins> ntim: might have implications in the Dom tree, sounds tricks<br>
&lt;TabAtkins> noamr: it's just in the layout tree, the box tree<br>
&lt;JakeA> q+<br>
&lt;JakeA> q-<br>
&lt;JakeA> q++<br>
&lt;TabAtkins> noamr: reproducing the doc VT case where the VT is in the top layer, a "sibling" to the doc<br>
&lt;astearns> ack +<br>
&lt;TabAtkins> emilio: is the idea that we don't want this in the top layer? we want it clipped by ancestors?<br>
&lt;TabAtkins> TabAtkins: yes, absolutely<br>
&lt;TabAtkins> JakeA: yes, in Shopify days we couldn't use VT in some cases because they wanted a VT on just a small piece of the page.<br>
&lt;TabAtkins> JakeA: they used VT:none on root to prevent that from animating, but then if they had a tooltip on top it would drop below the top-layer VT stuff, so they made *it* VT as well, whack-a-mole<br>
&lt;JakeA> astearns: doh, hah!<br>
&lt;JakeA> q-<br>
&lt;TabAtkins> emilio: if you have something in-flow, and you put something out of flow on top of it, that doesn't quite match the in-flow painting order.<br>
&lt;TabAtkins> emilio: it's painted by the abspos's CB, might be higher up<br>
&lt;kush> q?<br>
&lt;ntim> q+<br>
&lt;fantasai> TabAtkins: We've had some cases where we want to make it easier to select other containing blocks<br>
&lt;noamr> TabAtkins: we want to make it easier to select other containing blocks, e.g. your parent<br>
&lt;fantasai> ... in particular, your parent<br>
&lt;noamr> emilio: let's say you have a thing with overflow: clip and animating something inside of it. now you call startViewTransition on that. you effectively created an abs-pos on top. it would escape the clip<br>
&lt;noamr> emilio: clips of any ancestor from the scoped element to the nearest abs-pos<br>
&lt;noamr> TabAtkins: we want to enable it in the future<br>
&lt;noamr> emilio: sounds like it's a bit in the air<br>
&lt;emilio> ack emilio<br>
&lt;astearns> ack fantasai<br>
&lt;Zakim> fantasai, you wanted to comment on containing blocks<br>
&lt;TabAtkins> fantasai: I don't think anchorpos is the right solution for this<br>
&lt;TabAtkins> fantasai: you really do want to change the CB to this element. not by pos:rel, that is disruptive<br>
&lt;flackr> q+<br>
&lt;TabAtkins> fantasai: but we should have some way to say that the scope is the CB for that<br>
&lt;fantasai> https://www.w3.org/TR/css-position-4/#scrollable-cb<br>
&lt;TabAtkins> fantasai: some points to talk about why not do that. scorlling is one. we recently talked about three CBs generated by a scroller, one is the fixed CB, that's what you want<br>
&lt;TabAtkins> fantasai: so there are plans to add switches for that, should rely on that<br>
&lt;TabAtkins> fantasai: for the transform case, when you're contained by the transformed element you're in it so you're transformed with ti<br>
&lt;TabAtkins> vmpstr: the problem here isn't so much positioning, as trying to capture the effects on the scope itself<br>
&lt;emilio> q+<br>
&lt;TabAtkins> vmpstr: like a filter on the scope, the pixels you capture from that filter have to go into the VT pseudo-element. if that pseudo is also a child of the filter, then you're double-filtered<br>
&lt;TabAtkins> vmpstr: or circular if you want to prevent that<br>
&lt;flackr> not being filtered by the element, not being clipped by the element, etc<br>
&lt;TabAtkins> vmpstr: so it's less positioning, more about not being in the same filter tree/effect tree as the scope<br>
&lt;astearns> ack ntim<br>
&lt;TabAtkins> ntim: back to DOM mutations<br>
&lt;TabAtkins> ntim: say you move the scope element elsewhere in the tree. do you track the pseudo and move it at the same time?<br>
&lt;TabAtkins> ntim: otherwise you get z-order issues<br>
&lt;TabAtkins> TabAtkins: moving is a remove/add, so you cancel everything<br>
&lt;TabAtkins> JakeA: no, new method just moves it directly<br>
&lt;astearns> ack flackr<br>
&lt;TabAtkins> noamr: just need to make sure that's an issue we track<br>
&lt;astearns> ack emilio<br>
&lt;TabAtkins> flackr: yeah, confirming that this can't be a box child so we don't clip/filter it<br>
&lt;noamr> q+<br>
&lt;TabAtkins> emilio: I wonder, if you make this API parallel to the doc version, the doc version isn't in the doc itself, but the contents of the document<br>
&lt;TabAtkins> [not sure what that means or if I minuted it right]<br>
&lt;TabAtkins> emilio: instead of capturing the whole scope, you capture just the contents of the element, then the issue goes away<br>
&lt;TabAtkins> JakeA: my first draft did that, people just end up creating a wrapper div<br>
&lt;TabAtkins> vmpstr: we did consider that, but a very common use-case people do is "run on a div, change its background". but that won't work, background is part of the element itself not its contents<br>
&lt;TabAtkins> vmpstr: so we're really trying to make it so the scope itself is represented<br>
&lt;kush> q+<br>
&lt;TabAtkins> emilio: I wonder if we could define, rather than a sibling, it's a regular child but define special painting/capturing rules, in a VT the stacking context your box creates is in one place...<br>
&lt;TabAtkins> emilio: so the pseudo isn't a sibling in the box tree, but in the stacking context sense. one order that's for capturing VT, another for actual rendering<br>
&lt;TabAtkins> emilio: that solves layout issues, unsure if it adds more complications<br>
&lt;TabAtkins> emilio: but this is similar to what you do for the doc transition to capture the canvas background/etc<br>
&lt;TabAtkins> vmpstr: i'm not opposed to that, it's just more magic<br>
&lt;TabAtkins> vmpstr: it's more *explainable* with anchorpos, while this is pure magic. but I'm fine with that<br>
&lt;TabAtkins> noamr: initially this was my mental model, an anonymous container that holds the element and the VT pseudos<br>
&lt;TabAtkins> emilio: yeah, same way you can define the order in which stacking contexts are applied, you can define filter/transform/opacity, etc in a particular order to be correct. can define VT at a particular spot so it's outside the filters but within the element still.<br>
&lt;TabAtkins> noamr: only thing is it's less explainable in CSS terms<br>
&lt;TabAtkins> emilio: but still the same as the doc VT, yeah? doc transitions capture the canvas background, that's outside the document element. so I think this matches doc VT more closely.<br>
&lt;TabAtkins> emilio: if it makes the whole setup simpler should just do it<br>
&lt;TabAtkins> vmpstr: difficult part would just be describing transforms/etc. doc is affected by less than elements are.<br>
&lt;TabAtkins> emilio: sure<br>
&lt;TabAtkins> vmpstr: I think it's doable, just a little awkward<br>
&lt;TabAtkins> emilio: do you know off top of you head if transform is before or after filters?<br>
&lt;TabAtkins> emilio: [goes into a little more detail]<br>
&lt;TabAtkins> emilio: I find that model a bit easier, or more parallel to doc VTs<br>
&lt;TabAtkins> fantasai: makes sense to me<br>
&lt;TabAtkins> emilio: like if you apply filter to root, it doesn't just apply to root it applies to whole doc. but doc VT escapes that.<br>
&lt;TabAtkins> vmpstr: I also need to think through how the VT pseudos can be styled<br>
&lt;TabAtkins> emilio: same as in doc VT, the pseudo isn't affected by the VT styles<br>
&lt;kush> q-<br>
&lt;TabAtkins> JakeA: btw, it's filter *then* transform<br>
&lt;noamr> q-<br>
&lt;TabAtkins> emilio: so yeah that works, transform is applied on top after the VT is already positioned, so it follows along<br>
&lt;flackr> +1 that sounds like it could work<br>
&lt;fantasai> +1<br>
&lt;TabAtkins> astearns: so sounds like a different route. Vlad, do you want to explore implication in the issue, or just take a resolution?<br>
&lt;TabAtkins> vmpstr: might as well resolve, if we have issues we'll bring it back<br>
&lt;TabAtkins> vmpstr: resolution is to make the VT have a stacking context that's a sibling of the scope stacking context, but painted at a point before transforms/filters. Still a child of the box tree.<br>
&lt;TabAtkins> emilio: should we enforce the scope to be a CB for abspos? if you start a VT on a staticpos, the insets wont' work<br>
&lt;kush> q+<br>
&lt;TabAtkins> noamr: it's layout-contained, that already makes it a CB<br>
&lt;TabAtkins> kush: I was trying to understand - if it's a sibling in the box tree... sorry, a child, but it's painting involves all the content besides itself<br>
&lt;TabAtkins> kush: does it get the local clips?<br>
&lt;TabAtkins> emilio: probably not. ancestor clips apply, but on the element itself won't<br>
&lt;flackr> it should only be affected by the transform of the element<br>
&lt;TabAtkins> emilio: it'll be a painting layer defined,<br>
&lt;TabAtkins> kush: q is just if we make it a child of the scope, how many things that are inherited from the scope will have to be handled special<br>
&lt;TabAtkins> emilio: fair, but all those special things are what you want<br>
&lt;TabAtkins> kush: right, but we got all those special things for free by making it a sibling, they're manual now that it's a child<br>
&lt;TabAtkins> emilio: but many other things are easier as a child<br>
&lt;TabAtkins> vmpstr: what I think we really want is the scope to be the child of the VT<br>
&lt;TabAtkins> vmpstr: but that's... complicated<br>
&lt;TabAtkins> astearns: we're at time. should we not resolve yet?<br>
&lt;TabAtkins> kush: taking resolution seems fine for now, curious about what we'll learn impl wise<br>
&lt;TabAtkins> kush: i'm on the same side as Emilio, argued for that in my head, but other than moving the pseudo alongside the element, what am I gaining by the child approach rather than sibling?<br>
&lt;TabAtkins> emilio: you also get abspos CB for free, rather than it escaping all the clips up to its actual abspos CB<br>
&lt;flackr> +1<br>
&lt;TabAtkins> astearns: this is details. back to the question. objections to the proposed resolution?<br>
&lt;TabAtkins> RESOLVED: make the VT have a stacking context that's a sibling of the scope stacking context, but painted at a point before transforms/filters. Still a child of the scope.<br>
</details>


-- 
GitHub Notification of comment by css-meeting-bot
Please view or discuss this issue at https://github.com/w3c/csswg-drafts/issues/12324#issuecomment-3530620798 using your GitHub account


-- 
Sent via github-notify-ml as configured in https://github.com/w3c/github-notify-ml-config

Received on Friday, 14 November 2025 03:07:00 UTC