whatwg / html

HTML Standard
https://html.spec.whatwg.org/multipage/
Other
7.99k stars 2.61k forks source link

Consider adding `view-transition` as a token for `blocking` #10513

Open noamr opened 1 month ago

noamr commented 1 month ago

What problem are you trying to solve?

Render-blocking has been a mechanism for curating the incremental rendering experience, and avoiding layout shifts and FoUC. With the introduction of cross-document view transitions, render-blocking is now also used to delay rendering a bit until the expected content for the view-transition is available.

This can result in two unwanted scenarios:

What solutions exist today?

It's quite easy to create a script with setTimeout and unblock the elements. However, to know in advance whether there is an inbound view transition, the developer has to get that information in the pageswap event handler and save it to sessionStorage. This can be mess. Also none of these solution provide a default UA timeout.

How would you solve it?

Suggesting to add blocking="view-transition" for elements that support the blocking attribute. This attribute would work in the following way:

Anything else?

Alternatives: Expose hasViewTransition boolean in NavigationActivation. This allows knowing in advance if there is an inbound view transition without waiting for the pagerevealevent.

/cc @eeeps @chrishtr @zcorpan

khushalsagar commented 1 month ago

+1 to the idea. The VT spec already states that the browser should timeout the transition if the navigation is taking long. This token would also allow the UA to know which elements were blocking for a transition and timeout them at the same time.

zcorpan commented 1 month ago

blocking=render already allows a UA-defined timeout. Is this feature request because the timeout should be different for view transitions, or because it shouldn't block rendering at all if there's no view transition?

noamr commented 1 month ago

blocking=render already allows a UA-defined timeout. Is this feature request because the timeout should be different for view transitions, or because it shouldn't block rendering at all if there's no view transition?

Both! For the former, it's unclear what timeout is a good timeout for render-blocking. It's easier to reason about a short timeout for view-transitions as the result of it expiring is usually a skipped view-transition rather than unstyled content.

nickcoury commented 2 weeks ago

Thinking about this from a user-centric angle using guidance like https://web.dev/articles/rail and even personal experience, I have to imagine there's a small range for a good default render-blocking timeout in the 3-5 second range. Any longer and the navigation will start to feel quite broken and lead to significantly higher abandonment. I accidentally did this on a slice of traffic experimenting with cross-origin VTs and it showed up immediately in metrics. Much shorter than 3 seconds and it won't be long enough for many sites.

Another option if a developer wants a different timeout is to make it declarative: <link rel="expect" blocking="render" timeout="1000" href="#section1"> which would override the user agent behavior especially if a site knows its speed characteristics better. This is not just simpler than the JS solution, it allows longer timeouts than the UA default if desired.

After a short timeout (2s? 4s?) unblock the element and skip the view-transition.

Is there a reason to skip the view-transition, vs just running it with whatever elements are enabled? If I hit the timeout and was trying to wait for a shared element that didn't load fast enough, my preference would be playing the transition with the root element and whatever shared elements are available.

I suppose this might cause unexpected animations especially for the outgoing snapshots?

khushalsagar commented 1 week ago

Is there a reason to skip the view-transition, vs just running it with whatever elements are enabled?

It's the inverse, if the element was render-blocking only because it was required by a view transition and the UA has hit an internal timeout then the Document no longer needs to stay blocked on that element. In Blink that timeout is 4s.

noamr commented 1 week ago

Thinking about this from a user-centric angle using guidance like https://web.dev/articles/rail and even personal experience, I have to imagine there's a small range for a good default render-blocking timeout in the 3-5 second range. Any longer and the navigation will start to feel quite broken and lead to significantly higher abandonment.

VT aside, is showing unstyled content that may look extremely broken after 5s better? Hard to tell.

Is there a reason to skip the view-transition, vs just running it with whatever elements are enabled? If I hit the timeout and was trying to wait for a shared element that didn't load fast enough, my preference would be playing the transition with the root element and whatever shared elements are available.

I suppose this might cause unexpected animations especially for the outgoing snapshots?

Yea it's going to be hard to debug this as different race conditions would produce different animations.

nickcoury commented 1 week ago

VT aside, is showing unstyled content that may look extremely broken after 5s better? Hard to tell.

I would suggest yes as a default, a user on that slow of a connection/device likely already sees similar janky experiences on plenty of sites, and also has to decide based on visual feedback if their connection is stalled and they need to abandon or refresh. The visual feedback that something is still loading feels far superior to a frozen page with no apparent progress.

An explicit timeout would allow a site to say that they know better and want to wait longer if their situation truly justifies it, similar to how a page could choose to 'display: none' content if they really wanted.

The other solution would be a loading state, which VTs and render blocking don't have strong support for. I haven't tried, but perhaps it could be built on the outgoing page.

khushalsagar commented 1 week ago

@nickcoury an aggressive timeout could be considered for parsing/script where authors explicitly opt-in to render blocking. I'd be considered about compat if we did it for stylesheets which are render-blocking by default and have been for a long time now.

nickcoury commented 1 week ago

I was specifically thinking about the new tag since blocking on an #id seems inherently more risky if it's not actually in the doc. Agreed this wouldn't make sense to apply to all render blocking cases.