-
Notifications
You must be signed in to change notification settings - Fork 50
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Clarify what suppressing rendering means in terms of lifecycle updates #171
Comments
Seems like this is already possible, since SET already allows developers to 'hold' the current paint at their discretion: const transition = new SameDocumentTransition();
transition.prepare(async () => {
// The previous paint is now held.
updateTheDOM();
await document.fonts.ready;
// The animation starts after this callback has fulfilled.
}); |
Here's a demo: No waiting for fonts: https://simple-set-demos.glitch.me/waiting-for-fonts/without-waiting/ The difference between the two is |
For others reading, this should be paired with a timeout of sorts, such as 100ms as @sebmarkbage suggested: const wait = ms => new Promise(r => setTimeout(r, ms));
const transition = document.createDocumentTransition();
transition.start(async () => {
updateTheDOM();
await Promise.race([document.fonts.ready, wait(100)]);
}); |
Neat! Unfortunately, this doesn't seem to work with I suspect that's an under specified part of the spec because it's very subtle whether a font has been used or not. E.g. without transitions you can use this technique (in Chrome at least) to ensure that the font usage gets detected but then is not "shown" and so it doesn't trigger the permanent fallback state: document.body.innerHTML = ...;
const p = document.fonts.ready;
document.body.style.display = "none";
await p;
document.body.style.display = ""; I suspect something similar is necessary for transitions but I shouldn't have to hide it in this case since it's not really painted. |
Yeah, in the current implementation, while the paint is 'held', the only thing we're skipping is updating the pixels on the screen. We're going to change that so the render steps don't run at all (as if the display was 0hz). For example, right now, things like animated gifs will be 'running' in the background. With the change, it will ensure that the gif starts along with the first frame of the transition. |
Just as a note, we need to verify that the gifs that will be running are going to be in the background. Chromium's implementation drives gif animations from the compositor, so it's not immediately clear to me that skipping paint or skipping rendering altogether would have an effect on those. |
@vmpstr does that mean compositor-driven CSS animations won't pause either? That seems a little inconsistent |
Yes, I believe that's the case |
There is an open issue in the spec for clarifying what suppressing rendering means. The last meeting where we discussed this the conclusion was that all animations should be paused otherwise you have this inconsistency of which animation runs depending on the UA's implementation of what's threaded (like GIFs in Chrome's case). @jakearchibald @vmpstr does that conclusion align with you both? |
+1 |
Late to this conversation, but, in what ways is this related to image decoding=sync? As far as I know decoding=sync will also "block rendering", and also somewhere down stream from Paint (at least in chromium), but does not block declarative compositor-driven animations/scrolling updates. I think that means that "Activate" stage is blocked? And it may also have a timeout? |
(All in Chromium terms) You're right that decoding=sync will block activation until the rasterization of affected images is done. This does mean that ongoing active tree animations will continue producing frames. For this feature, we're blocking both main and impl frames which means that even the active tree will not produce new frames, after the initial one that requests the snapshot which needs to be forwarded to the gpu stack. This means that active animations, gifs, etc will all be "paused" |
The sync decoding case would not have a timeout. FWIW, the default decoding value is 'auto' and in Chromium that should be equivalent to 'sync' (iirc), so when we're talking about decoding=sync, that's just the default state |
Thanks @vmpstr! Regarding a question @sebmarkbage asked up top, about how this relates to the There are a few distinct uses for the phrase "render-blocking":
My read of the My read is that SET needs some way to spec (2). And (3) I know I use use to explain overly long paint-timings (i.e. FCP, LCP, INP, etc) which are specifically due to rendering issues. There is already the concept of We have existing issues in terms of paint timing and element timing spec due to underspecified nature of parallel animation frame updates, which we would like to also be able to address. |
SET is going to use render blocking to explain how rendering is suppressed. For cross-document navigations, suppressing rendering of the new Document until is ready for transition will be controlled by "render-blocking". For the same-document JS API, I was planning to expand the text here to include transition suppressing rendering as one of the reasons a document doesn't have rendering opportunities. The spec language will need to ensure a transition suppresses rendering for all nested documents as well. Also this was recently discussed in the issue here which has a summary of the discussion and the resolution. |
Closing this issue given the resolution on the csswg issue. Please feel free to continue the discussion there if there are more questions. |
In Chrome there's a heuristic to delay paint for 100ms on initial page load if a font is preloaded and optional. This is great because it avoids flashes of invisible text.
I'm not sure how/if this part will ever be spec:ed. Ideally this could also be used with other display modes to avoid the CLS if possible. This is also related to the font-display: critical proposal.
One problem with these heuristics is that they only work for initial load. For SPA transitions it doesn't work. If you navigate to a new page that uses a font there's no way to delay the paint because everything paints as soon as possible - when there's some pending DOM mutations.
We can do some stuff to delay the DOM mutations in frameworks but because detecting if you actually use something requires apply styles which require DOM mutations makes this tricky to implement efficiently and easy to use, because there's no way to create an optimistic DOM tree for what might be rendered unless you have a way to revert any changes.
However, shared-element-transitions do have some of those capabilities at the painting layer. You could effectively delay the animation from starting if painting the new element would be missing a font.
So my proposal is to allow shared element transitions to automatically delay playing the animation for up to 100ms if a new element entering or element with updated text styles/content is still waiting on a font-face to load - under the same heuristics that apply for initial paint. In other words, wait to paint the "target screenshot" until the fonts have loaded or some timeout.
Delaying animations might be somewhat controversial since it can delay the feeling of responsiveness but it can also be better sometimes. Therefore this could be some extra option to the transition that opts into waiting for some heuristic.
The text was updated successfully, but these errors were encountered: