I was mystified the other day about why some navigational View Transitions weren’t working for me. It was just a demo thing, so it wasn’t a big deal, not to mention this API is Chrome-only and just a progressive enhancement anyway. But I did learn why!
The way I understand it now is that navigation View Transitions (these are the kind that happen between clicking links to load new pages) do not interfere with performance by default. I was under the misconception that they potentially could.
For example, let’s say I have a whole bunch of preview blog post “cards” on a homepage, like:
<div class="card" style="view-transition-name: blog-post-3245;">
<h3>Blog Post Title</h3>
<p>Lorem ipsum dolar...</p>
<a href="/blog/article/cool-post">Read the article "Cool Post"</a>
</div>
<div class="card" ...
Then the actual blog post page has HTML like:
<article style="view-transition-name: blog-post-3245;">
<h1>Blog Post Title</h1>
<p>Lorem ipsum dolar...</p>
...
Note the matching view-transition-name
. If you’re in a supporting browser (just Chrome, as I write) and you’ve done this little incantation in your CSS:
@view-transition {
navigation: auto;
}
Now you’ll see that <div>
card magically and gracefully transform into that <article>
through the power of View Transitions (which you can fully control in CSS).
Well, maybe.
In order for that View Transition to work (and not just bail out and page transition normally with no fancy animation), the new/incoming page will need to fully render the element with the matching view-transition-name
in the “first paint” (I might have the terminology wrong here, not sure).
This is where the performance stuff comes in. I was under the misconception that the browser would wait to figure out if there were elements with matching view-transition-name
s on the new/incoming page so that it could make sure the view transition happens. But it will not wait! It will load the page just as normally/quickly as it always has. If it so happens there is a fully painted element with a matching view-transition-name
, it’ll do it, if there isn’t, or it just hasn’t found or finishing rendering one yet, it’ll bail.
That’s good… I think?
We don’t need any more performance footguns, and this one seems all to easy to become a render-blocker.
On my little test page thingy, I was seeing the view transition happen maybe 50% of the time (right now as I test it feels more like 5% of the time). That kinda makes sense to me. I was rendering images here, maybe they just aren’t making that first paint sometimes or even most of the time, and thus the view transition bails.
But who wants to work on View Transitions that run 50% or less of the time? That’s just… weird?
The answer seems to lay in render blocking. Render blocking sounds bad, and it kinda is, but we rely on it for various stuff fairly regularly. If you have a client-side rendered JavaScript-framework site, you’re essentially render blocking already. You might render block in order to avoid any Flash-Of-Unstyled-Text which was fashionable at one time. You might render block to avoid content shifting of any kind.
Now you might render block for view transitions because: you want the view transitions to work. The answer, for now, seems to be in the form of a <link>
like:
<link rel="expect" href="#lead-content" blocking="render" />
That’s ID-based, so you’ll need to put IDs on any element you want to behave as a render-blocking element. Little hassle, but OK I guess. I’ve heard you might be able to do this on the element itself with an attribute at some point, which makes a bit more sense to me.
I’d love to tell you that this is the answer and if you do it right you’ll have working navigational view transitions every time, but I tried it and it didn’t seem to work for me. I assume I’m doing something wrong, so I’ll fix up that demo if I learn what it is.
If you’re interested in more about this render blocking stuff, Harry Roberts has a good why would you do that?! post. Here’s a few more performance related links burning a hole in my pocket: