Skip to content
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

Support View Transition API for navigations #935

Merged
merged 1 commit into from Jun 27, 2023

Conversation

kevinmcconnell
Copy link
Collaborator

Adds the ability to use the View Transition API. It's based around the MPA View Transition support which is currently becoming available in Chrome.

When navigating between pages, we check for the presence of view-transition meta tags in both documents, with a value of same-origin. If those tags are present, and the browser supports the View Transition API, we can render the page update within a transition.

view-transition

When not opted in with the meta tags, or when support is not available, we fallback to the previous behaviour.

This mimics the behaviour that a supporting browser would have when performing a full-page navigation between those pages.

We also suppress snapshot caching on pages that specify these meta tags, since the snapshots would interfere with the animations.

Note although we're copying the API of MPA view transitions, the implementation only requires SPA view transitions (since we aren't doing a browser navigation). SPA view transitions are already available in the latest Chrome versions.

Also note this is based on an API that is very new, and not yet widely supported. We'll want to keep an eye on how that develops and update our implementation accordingly.

Adds the ability to use the View Transition API. It's based around the
MPA View Transition support which is currently becoming available in
Chrome.

When navigating between pages, we check for the presence of
`view-transition` meta tags in both documents, with a value of
`same-origin`. If those tags are present, and the browser supports the
View Transition API, we can render the page update within a transition.

When not opted in with the meta tags, or when support is not available,
we fallback to the previous behaviour.

This mimics the behaviour that a supporting browser would have when
performing a full-page navigation between those pages.

We also suppress snapshot caching on pages that specify these meta tags,
since the snapshots would interfere with the animations.

Note that while the API is based on MPA view transitions, the
implementation on requires SPA view transitions, which is already
available in the latest Chrome versions.

Also note that this is based on an API that is very new, and not yet
widely supported. We'll want to keep an eye on how that develops and
update our implementation accordingly.
@domchristie
Copy link
Contributor

Exciting stuff ✨

What are your thoughts on providing a way to dynamically change view-transition-names?

The View Transition guide demonstrates an approach that adds a view-transition-name for the duration of the transition only. This is particularly beneficial when transitioning from an index to a show: you might have lots of thumbnails that could transition to a larger version on show. Without dynamic view-transition-names, each image would have to have a unique view-transition-name (e.g. post-image-123), which makes it difficult to customise the pseudo element behaviour with CSS, since the names need to be known i.e. there's currently no wildcard matching like ::view-transition-old(post-image-*). (Perhaps there are plans for this in order to support MPA transitions?)

Anyway, perhaps it'd be useful to support this in some way? Ideally the view-transition-name could be customised based on the link that initiated the visit. I think the safest place for this would be in the turbo:before-render event (rather than turbo:click which is cancellable). But for this to work, we'd need a reference to the initiator element, and something like #750.

Here's an example of what it could look like:

<a href="/posts/1" data-view-transition-name="post-image"><img /></a>
<a href="/posts/2" data-view-transition-name="post-image"><img /></a>
<a href="/posts/3" data-view-transition-name="post-image"><img /></a>
addEventListener('turbo:before-render', function ({ target }) {
  target.style.viewTransitionName = target.dataset.viewTransitionName
})

@domchristie
Copy link
Contributor

there's currently no wildcard matching like ::view-transition-old(post-image-*). (Perhaps there are plans for this in order to support MPA transitions?)

Might be worth keeping an eye on: w3c/csswg-drafts#8319

Copy link
Collaborator

@afcapel afcapel left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great, nice job! 👏

src/core/drive/view_transitions.ts Show resolved Hide resolved
@kevinmcconnell
Copy link
Collaborator Author

@domchristie thanks for the feedback!

What are your thoughts on providing a way to dynamically change view-transition-names?

Yes, I think that's a great idea! I agree that it would be very useful, and the way you've described it there sounds like a good plan.

Let's start with this PR to add the initial support for view transitions, and then we can explore dynamic transition names in another PR.

@kevinmcconnell kevinmcconnell merged commit 151aca2 into main Jun 27, 2023
2 checks passed
@kevinmcconnell kevinmcconnell deleted the view-transition-support branch June 27, 2023 21:00
@domchristie
Copy link
Contributor

We also suppress snapshot caching on pages that specify these meta tags, since the snapshots would interfere with the animations.

It should be possible to work with Turbo's cache, as long as you only animate on the first render i.e. if the visit has a preview, only animate that and not the fresh response; otherwise, render the response. This is the approach taken in Turn: when rendering a visit with a preview, it waits until the preview has animated before rendering the response. Live demo here: https://domchristie.github.io/turn/examples/view-transitions-only/, and the code that tracks the previews: https://github.com/domchristie/turn/blob/4f54843aedb01df5b84875fa9fa0a8ddb2f672ed/src/controller.js#L39-L57

@kevinmcconnell
Copy link
Collaborator Author

@domchristie I had tried that, but in practice any changes between the snapshot and the fresh view looked distracting. Animating in the new content can look really nice, but if that content suddenly snaps over to something else at the end it can spoil the effect. Skipping over the cached preview seems like a safe bet to make sure it always looks smooth.

I imagine it depends a bit on the use case too, though -- how much your snapshot is likely to be out of date, and what sort of transition you have. So it could be worth adding a way to override this with cache control.

@domchristie
Copy link
Contributor

but in practice any changes between the snapshot and the fresh view looked distracting

I think that applies to both animated and non-animated navigations, so I think it should be up to the developer to add the cache control directives for their own cases.

Skipping over the cached preview seems like a safe bet to make sure it always looks smooth

Does this PR also impact Back navigations? i.e. if isCacheable is false for view transition views, then it won't be cached and therefore tapping back will make a request?

@kevinmcconnell
Copy link
Collaborator Author

@domchristie it was more about wanting the behaviour to look good by default. This way if pages are using view transitions, it's more likely that they'll look good in Turbo, without extra effort. I think animated transitions and snapshots don't tend to work well together, and also that snapshots are something that we should be happy to suppress whenever they aren't adding to the experience.

(Kinda similar to the way we purge all the snapshots after any sort of mutation; they may or may not still be accurate at that point, but it's better to not have one than to have one that gives a poorer experience).

Happy to look at alternatives too though, if you feel strongly about trying a different approach!

@domchristie
Copy link
Contributor

I think animated transitions and snapshots don't tend to work well together

I think this largely depends on what type of app/site it's running on. In many cases the switch won't be noticeable, but if it is noticeable, then there are reasonable options to solve it: either through cache control directives, Turbo.cache.clear, or even data-turbo-permanent.

snapshots are something that we should be happy to suppress whenever they aren't adding to the experience.

I suppose they are adding to the experience because they're making repeat visits and back navigations faster.

@kevinmcconnell
Copy link
Collaborator Author

Let’s give it a go, and we can compare. As I say, totally happy to change things for the better here. This PR was really intended to add the basics, and we can build on it to iron out the details.

I’ll try to look at it some more this week, but if you get there first that’s fine too :)

And thanks again for your feedback here, it’s always very helpful 🙏

@domchristie
Copy link
Contributor

Sounds great. Thanks for adding this!

afcapel added a commit to hotwired/turbo-site that referenced this pull request Jan 25, 2024
afcapel added a commit to hotwired/turbo-site that referenced this pull request Jan 25, 2024
afcapel added a commit to hotwired/turbo-site that referenced this pull request Feb 7, 2024
* Document view transitions

Introduced in hotwired/turbo#935 and
hotwired/turbo#1007

* Better css example

Co-authored-by: Dom Christie <christiedom@gmail.com>

* Add data-turbo-visit-direction to attributes reference

* Be more precise

Co-authored-by: Dom Christie <christiedom@gmail.com>

* Document meta tag

* Clarify it’s optional

Co-authored-by: Kevin McConnell <kevin@37signals.com>

---------

Co-authored-by: Dom Christie <christiedom@gmail.com>
Co-authored-by: Kevin McConnell <kevin@37signals.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants