csswg-drafts
csswg-drafts copied to clipboard
[css-view-transitions-1] content-visibility: auto elements are relevant to the user during a transition
content-visibility: auto
allows the user agent to minimize the rendering cost for elements which are not relevant to the user. There are multiple subtle interactions this optimization has with View transitions.
-
Identifying elements with a valid
page-transition-tag
(and other constraints) requires all elements to have up to date style (see logic here). Offscreen elements can also participate in a transition since the transition might bring them onscreen. Socontent-visibility: auto
shouldn't prevent discovery of a tagged element.The default behaviour would be for the transition to force style update for the whole DOM tree to discover tagged elements. We can add an option going forward (new
contain
keyword?) for the author to indicate that a sub-tree doesn't have tagged elements. -
If an element with
content-visibility: auto
is tagged, it becomes relevant to the user. -
If an element with
content-visibility: auto
has a descendant which is tagged, the element becomes relevant to the user. This is because we need to layout/paint the tagged element to render it in its corresponding replaced pseudo-element. -
If an element with
content-visibility: auto
has an ancestor which is tagged then we have 2 cases:- If that ancestor is the root element then
content-visibilty: auto
can continue to apply. This is because the root snapshot is clipped to the viewport. See #7859 for details. - If that ancestor is a non-root element then the
content-visibility: auto
node becomes relevant to the user. This is because snapshots for non-root elements are painted in their entirety (modulo hardware constraints).
- If that ancestor is the root element then
@vmpstr to validate the summary.
We had an offline discussion about this, summarized below. There are 2 different points to resolve for this issue:
-
If an element is participating in a transition, any element in its sub-tree (which has c-v: auto) should become relevant to the user. This makes sense given that the tagged element will be painted into a snapshot. This snapshot's position and scale is animated during the transition (by the pseudo-element its drawn in). So all its content (including the c-v: auto elements) could be in the viewport.
Given that the snapshot for all non-root elements paints the entire DOM tree underneath, it'll make all c-v: auto elements underneath a non-root tagged element relevant to the user. It's only the root (for which the snapshot is clipped) which can have c-v: auto elements underneath that are clipped out of the snapshot and hence don't need to be made relevant to the user.
Proposed Resolution: An element with
content-visibility: auto
is relevant to the user if it is painted into self or an ancestor's snapshot during a transition. -
Deciding which elements participate in a transition requires resolving style on all DOM elements so the computed value of
page-transition-tag
property is known. This forces resolving at least style for elements withc-v: auto
. That defeats the purpose of the optimization. There are 2 choices:-
By default force style resolution on the whole DOM to find all tagged elements so
c-v: auto
doesn't influence whether a tag works. The developer will have no way to retain the optimization beyond temporarily addingcontent-visibility: hidden
if they don't need tags under a DOM subtree to be discovered. We could add acontain: view-transition
for the developer to directly express that intent. -
Elements under a
c-v: auto
element which is not already relevant to the user can't participate in a transition. "Relevant to the user" can be different across browsers since margin around viewport is user-agent defined. If the developer wants elements to always be discovered they can switch toc-v: visible
for the transition.
Proposed Resolution: When traversing the DOM to discover tagged elements only visit elements relevant to the user. Updates step 4 here and here changes to "For each element and pseudo-element connected to document and relevant to the user".
-
What happens if you call getBoundingClientRect
on an element within a hidden content-visibility: auto
region?
If that gives a result as if the element is not-rendered, then I think View Transitions should also treat the element as not-rendered.
getBoundingClientRect
is fine for the element with content-visibility: auto
since that element has been styled/laid out. But if you call it for one of its descendants, it forces a style/layout and causes the browser to do work it had optimized out.
Huh, that's surprising.
Triggering a potentially large layout in the middle of a page switch is definitely a bad thing. I'm kinda surprised that content-visibility
de-opts when querying particular layout info.
We talked about another feature elsewhere https://github.com/WICG/view-transitions/issues/84, that changed the behaviour of elements outside the viewport. If you opt-in to treating outside-viewport elements as "not rendered", then you avoid the heuristic behaviour of content-visibility
.
Thinking it through, I still think we have the right default - transition things from their original position. That works well for most use-cases.
It doesn't work well for cases like a header transition. If the header can be scrolled away 1000s of pixels, having it transition back to the top is a bad transition. You can work around this with JS pretty easily by tagging the header dynamically if it's in the viewport, but a high-level way of doing that seems reasonable, but I don't think we need it for MVP.
If a grid of items is transitioning in a way that makes them shorter, that may result in additional rows entering the viewport. In this case you really want them to animate from their original positions, even though they were outside the viewport.
I understand content-visibility
a bit better now. Specifically: the changes in the container size are observable, but the layout skipping of the content is not supposed to be observable.
So, I guess we're talking about doing something different than that for view transitions? Yeah, that doesn't seem great, but I don't think there's a better option.
I guess we're talking about doing something different than that for view transitions
Yes. getBoundingClientRect will force style/layout for a node which is "not relevant to the user" and is in locked state. One difference between this and view transitions is that the forced style/layout only happens if the developer queries this info from script.
With view transitions if we take the same pattern we'll have to force style resolution for the entire DOM even if there is no node with a view-transition-name
under a content-visibility: auto
node. There also won't be a way for the developer to indicate that no such node exists and the browser can avoid the style walk without an explicit property (like contain: view-transition-name).
That's why I'm more inclined to skip discovering view-transition-names under a DOM node if its not relevant to the user. And letting authors use content-visibility: visible
if they want such names to be discovered deterministically.
The CSS Working Group just discussed [css-view-transitions-1] content-visibility: auto elements are relevant to the user during a transition
, and agreed to the following:
-
RESOLVED: elements under content-visiblity:auto element that skip its contents are not eligible to participate in view transition
The full IRC log of that discussion
<fantasai> Topic: [css-view-transitions-1] content-visibility: auto elements are relevant to the user during a transition<fantasai> github: https://github.com/w3c/csswg-drafts/issues/7874
<fantasai> vmpstr: content-visibility: autho not user relevant, they don't update rendering, so we can't tell if they've been tagged with a view transition name
<flackr> q+
<fantasai> vmpstr: so we'd like to say that such elements that are not relevant to the user can't participate in the view transition because they're far enough offscreen
<fantasai> flackr: my preference was element can participate, because could move on screen, but none of its descendants
<fantasai> vmpstr: sorry, meant the subtree elements cannot be detected as participating in this transition
<Rossen_> ack flackr
<fantasai> vmpstr: content-visiblity: auto only affects content
<fantasai> flackr: with that correct, good with that
<fantasai> Rossen_: proposal?
<fantasai> vmpstr: elements under content-visiblity:auto element that skip its contents cannot be discovered as participating in view transition
<flackr> +1
<fantasai> s/cannot/are not eligible to be/
<fantasai> florian: seems reasonable
<fantasai> +1
<fantasai> Rossen_: objections to resolving on that edited proposal?
<fantasai> RESOLVED: elements under content-visiblity:auto element that skip its contents are not eligible to participate in view transition