Open khushalsagar opened 6 months ago
Summarizing an internal sync:
After the capture is done, we can throttle and do the same thing as we do with other CSS animations: run them eventually
The downside here though is that we keep snapshots cached which is unnecessary memory for offscreen content. It also involves forcing rendering of offscreen content. https://github.com/w3c/csswg-drafts/issues/8282 could help with it but it's an opt-in. And it seems unfortunate to allow an iframe (potentially cross-origin) to slow down the main frame even when its offscreen because they didn't use this optimization.
My inclination here is to skip the transition if the iframe goes offscreen, similar to visibility. With some UA defined margin around the viewport to decide whether its offscreen in case scrolling brings it onscreen while the update callback is running.
Summary for another conversation on this, it's between the follow options. "Current Behaviour" is least preferred but mentioning for completeness.
If an offscreen iframe starts a ViewTransition force it to render, i.e., the UA is not allowed to throttle an iframe with a ViewTransition. We can relax it to say that this force mode is applicable until the pseudo-DOM is set up and animations (UA or author provided) have started.
Because once the animations have been setup, it's no different from a regular CSS or web animation on the page. The animation progresses based on its timeline an the UA can optimize rendering similar to other offscreen animations. When the animations finish, all the setup will be torn down.
The pro for this is it better aligns with how CSS and web animations work on the platform today, its not web observable whether the content is offscreen. And avoids edge cases where the iframe comes onscreen while the updateCallback
is running, resulting in a flash of intermediate DOM state.
The con is its suboptimal. Regular CSS or web animations don't force the browser to render offscreen content, while this will because the old DOM state will be torn down. So it consumes compute and memory for content never shown to the user. It's also a footgun, both the main and iframe might not realize that transitions in offscreen iframes are costly.
If the iframe is offscreen (based on a UA defined margin), transitions in it are skipped. The behaviour is the same as the Document being hidden, spec'd here and here.
The pro/cons for this is inverse of "Force Rendering". Its more optimal but can result in flashing of intermediate DOM states if the iframe is scrolled offscreen. For example, an abrupt change in scroll position using scrollbars.
The behaviour in the spec today is that after script calls startVT, the VT object is created and it waits for a rendering lifecycle update to cache the next frame. If the iframe is throttled, that rendering update won't happen until its un-throttled. So the iframe's VT would be blocked from starting until then.
The pro for this is that it takes care of both: don't use resources for offscreen content and don't flash intermediate DOM states. But it defers updating the DOM so the user unnecessarily sees stale content when the iframe comes onscreen. It's also possible the author is deferring some work until the transition's finished promise resolves, which is also delayed.
@nt1m @emilio fyi.
The CSS Working Group just discussed [css-view-transitions-1] Handle startVT for offscreen iframes
.
@flackr interesting question post the resolution, how should we handle web animations? Especially since they can be chained. The author might use the finished
promise of 1 web animation to start another web animation. Do we keep adding the delta for how long the iframe was offscreen before the transition started to all animations associated with that transition.
If they're chaining promises, I think it would be up to them. This is no different then if you chain promises on regular web animations for content in a far away frame that they'll only start at the point where the lifecycle updates to trigger the finish promise and it would be up to the developer to apply a negative start delay if they want to start the next animation when the previous one finished from a time perspective.
This is no different then if you chain promises on regular web animations for content in a far away frame that they'll only start at the point where the lifecycle updates to trigger the finish promise
So for regular web animations, we decide the start time at the time the author calls element.animate
. But if the animation reaches its end time while its still offscreen, we won't fire any events for it until it comes onscreen..? Is that consistent across browsers? I have a memory of this coming up in person with @emilio.
I think so since animation events are fired from the rendering update code right?
Btw, the side track of trying to improve interop here with iframe throttling is https://github.com/whatwg/html/issues/10333
I think so since animation events are fired from the rendering update code right?
The timelines section of the web-animations-1 spec covers animation events, in particular:
When asked to update animations and send events for a Document doc at timestamp now, run these steps: ...
- Let events to dispatch be a copy of doc’s pending animation event queue.
- Clear doc’s pending animation event queue. ...
- Dispatch each of the events in events to dispatch at their corresponding target using the order established in the previous step.
So yep, they are fired as a result of the "update the rendering" steps.
Cool. So seems like for parity with general animations, we would delay the startTime of the animations targeting pseudo-elements in the first update-the-rendering loop after the pseudo-elements are generated. Post that, all animations (CSS transitions, animations or web animations) get their start time as usual.
There's also the matter of the update callback time here. So, the current events we have are:
t0: startViewTransition is called t1: capture is requested** t2: capture completes t3: callback starts*** t4: callback ends t5: pseudos are created and animation is ready to start
** this includes the request being unblocked to propagate wherever it needs to, not just pending *** t2 and t3 are generally the same time, iirc
At t5 right now, the animation progress time is 0. The proposal is to set the progress to something like (t5-t0) so the animation conceptually starts when startViewTransition is called. However, we also discussed excluding some times like the capture turnaround (t2-t1). I think we likely also want to exclude callback runtime (t4-t3)?
So, would then should the initial progress of the animation at t5 be (t1-t0)? This is reasonable for css animations. However, for web animations that start at the ready promise resolution (t5), it seems a little awkward to start that animation with non-zero progress and presumably only the animations that target the vt pseudos. This makes coordinating multiple animations difficult, imho.
It's unclear what should be done when an iframe is offscreen and rendering opportunities for it are throttled, see spec for that state here : "Remove from docs all Document objects for which the user agent believes that it's preferable to skip updating the rendering for other reasons".
It's unclear how ViewTransitions should be handled in this state. Suppressing rendering opportunities implies that the behaviour differs based on when that happens. If its before the old state was snapshotted, we'd hit a timeout and abort the transition. If its after the pseudo-DOM was setup, then its similar to the author starting CSS animations on an offscreen Document. It's probably better to have consistent behaviour here.
The decision for this should likely also influence scoped transitions? If the root element of that transition is offscreen for example.