-
Notifications
You must be signed in to change notification settings - Fork 677
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
[css-view-transitions-2] Syntax for navigation-matching #8925
Comments
I think I like the direction of this, but some of it isn't clear to me. Can you show some code for a basic slide-from-the-side transition between two particular URL patterns, that would work for both MPA and SPA, and both push navigations and traversals? |
Sure! // These are dynamically rendered on client-side (SPA) or server-side (MPA) to match the relevant URL pattern.
// e.g. the following would be rendered when the URL matches `/slide2`:
@navigation prev-slide {
target: urlpattern(/slide1);
type: navigate, back-forward;
}
@navigation next-slide {
target: urlpattern(/slide3);
type: navigate, back-forward;
}
//////
::view-transition-old(root) {
animation-name: none;
}
@media (navigation: next-slide) {
::view-transition-new(root) {
animation-name: slide-in-from-right;
}
@media (navigation: prev-slide) {
::view-transition-new(root) {
animation-name: slide-in-from-right;
animation-direction: reverse;
}
} The idea is that we don't need to know the "current" URL, the framework or whoever already knows this. So all the navigation rules apply to the target URL, whether it's the next or the previous one. In this scenario we only affect the pseudo-elements so we don't need to worry about outgoing transitions. |
That doesn't seem quite right, as it would result in a partial sliding animation if going from next-slide to some other kind of page. I'm still not sure how I'd use this in an SPA. How would I activate these rules in an SPA? |
What's the benefit in separating |
Sure, need to play with it with a class-based polyfill, hard to whiteboard the exact thing.
function Slide({index: number}) {
return <>
<style>{` // dangerousReactHTMLStuff or a style component or whatever
@navigation from-prev-slide {
target: urlpattern(/slide${index - 1});
}
@navigation from-next-slide {
target: urlpattern(/slide${index + 1});
}
`}</style>
<main>{slideContent[index]}</main>
</>
}
|
Probably in most cases you won't, so I think one of the main use-cases for the navigation-type is actually to enable/disable animation on reload (#8784). |
I still don't think I'm seeing a full example here, and it's already looking complicated to do part of an extremely basic example, which suggests the design has gone wrong somewhere. For contrast, here's how I'd do the slide-between two pages example based on the proposal in #8683: @media (vt-next-page: urlpattern('/foo')) {
@cross-document-transition allow;
}
@media (vt-old-page: urlpattern('/foo')) and (vt-page: urlpattern('/bar')) {
@cross-document-transition allow;
::view-transition-new(root) {
animation-name: slide-from-right;
}
::view-transition-old(root) {
animation-name: slide-to-left;
}
} Then, to make it work in SPA too: document.startViewTransition({
oldURL: '/foo',
newURL: '/bar',
update() {
// update DOM here
}
}); Where And that's a full example, and it didn't need frameworks, generated CSS etc etc. |
The one stated in the issue: Transitions tend to happen in the opposite direction on 'back' navigations. Note that this doesn't just mean reversing the animation.
I think it'll be super-rare or even plain undesirable to want transitions on reload, so I'd just make that an extra opt-in, or just don't allow it to happen. |
How do you disable reloads or give them a different animation in this example? It seems great when it's simple but when you want to tweak it you might end up with monstrous media-queries. Also, this is VT-specific. By having this as "navigations", you could style other things based on where you're coming from. Regarding having the URLs in the @navigation to-foo{
to: urlpattern(/foo);
type: navigate, back-forward, reload; // reload OK!
}
@navigation foo-to-bar {
from: urlpattern(/foo);
to: urlpattern(/bar);
}
@media (navigation: to-foo) or (navigation: foo-to-bar) {
@cross-document-transition allow;
}
@media (navigation: foo-to-bar) {
::view-transition-new(root) {
animation-name: slide-from-right;
}
::view-transition-old(root) {
animation-name: slide-to-left;
}
} btw this is a push animation and not a slide animation. |
The thing with putting URL pattern in the media-query, is that if your routes change you have to update all of them, and you might have many. Sprinkling navigation routes all around CSS files seems brittle. So by putting them in their own rule we can achieve several things:
The other parts of this proposal are perhaps what makes it seem complicated for the slides case:
I think I'm OK with keeping the rule but spelling-out the to/from both in the rule and in the |
Like I said, I'm not sure allowing transitions for reloads is a good idea. But, if we really wanted it, I'd make it part of the opt-in rule, and add a media query for it.
Can you give an example?
Maybe? But, making it work badly for VT because of some unknown non-VT use-case seems bad.
Right, this is why I was asking you for an example, because I couldn't see how 'automatic' ways of doing it would fit in with the timing of same-document navigations and traversals.
Huh, I didn't realise there were official names for these types of animations. Where are they defined? By 'slide' I was meaning that the new content slides in from the right (or left if it's 'back'), and the old content slides out to the left (or right if it's 'back'). But, the specific animation doesn't really matter, other than it's directional and between two specific pages.
Agreed. When I said "I think I like the direction of this" I was referring to creating named definitions. I think that's a good idea. Btw, I'm not saying the existing ideas I've summarised in various issues are perfect or even good, but they were thought-through, so they're a useful basis for comparison.
Yeah, I think exploring this further is a good idea. Just test it against basic examples, and ensure that it works for SPA too, so developers don't end up with multiple definitions for the same animation between two 'pages'. If options are added to |
@jakearchibald btw with the URLs in the SPA case, perhaps we don't need new parameters? // old URL is the current document URL when the old state is captured
document.startViewTransition(() => {
// new URL is the document URL when the new state is captured.
history.push(newURL);
}); |
I don't see how that would fit in with the timing of same-document traversals. Being able to control when the URL is updated for any navigation is still experimental in the navigation API WICG/navigation-api#66 (comment) |
Oh because the document's URL is the new one on |
Yeah, that might be nice and forward-looking. document.startViewTransition({
urls,
update() {
// update DOM here
}
}); Where
Maybe that's a bit of a weird API shape, since |
In general I like the idea of |
Hmm, not all view transitions are "page" transitions. That's why I don't think the media queries should apply by default. |
@jakearchibald before going into the exact syntax, I want to make sure we're all on the same page about the following:
@media (vt-next-page: article) {
/* … */
} where
|
Right, it should use the initiated navigation's URL in the old document, and the actual URL in the new document. Authors should be aware of this.
I am thinking that these concepts would be automatic for MPA navigations, and at first manual for SPA navigations, with an option to enable automatic navigation detection later when we allow declarative SPA transitions (something I'm really keen to do in the future). The latter would require careful integration with the timings of the navigation API, Perhaps for SPA transitions we don't even need to pass the URLs, but rather just the navigation names, e.g. startViewTransition({update: () => {...}, navigations: ["foo-to-bar"]}) |
Yeah, I understand the technical limitations around this.
There are pros and cons to that. The pros are it becomes a general navigation feature, which feels nice in terms of platform structure (although view transitions would still have an impact on the lifetime of these rules), but some cons:
Given the issues around the URL change, I don't think declarative SPA transitions offer a lot of value. The developer would need to use the opt-in, switch their routing to the navigation API, enable manual entry committing, and ensure they commit the entry at the correct point. This seems like orders of magnitude more work than just using
I don't think these navigation definitions should include both the old and new URL patterns. I see the benefit of defining a bunch of paths as a particular page type, but forcing the rule to include both patterns just reintroduces the repetition in a different place. For example, if you have 4 page types, "index", "article", "gallery", "search-results", and some customisation of transitions between them, you now have 16 definitions:
Unless I'm missing something, you'd end up declaring the same URL patterns 8 times each. Instead, it seems better if there's a way to define a page type from a bunch of URL patterns, then they're only defined once each. |
You can still use the regular view transitions and apply classes or what not, the media queries are specifically for the cases where you want the transitions to automatically react to a navigation.
I think we should advance declarative same-document transitions once the navigation API gets into shape. Yes, it has a few issues but I think it would be amazing if "some day" we could have same-document experiences that don't require loads of JS.
Yup, right now it is. I hope that on top of some of the primitives of the navigation API we could make some of this stuff declarative in the future, where transitions between routes/hashes are declarative. But I wouldn't rush to it.
Probably 8: @media (navigation: from-search-results) and (navigation: to-gallery) {
} The alternative is perhaps nicer: @media (navigation: from search-results to gallery) {
} I was proposing the former because it is perhaps more extendable in terms of defining things about the navigation itself rather than the page type (e.g. opt-in for back-forward, or special-casing cross-document). We should examine if those customizations are common enough to be part of the definition, or if putting them directly in the media-query is sufficient. |
This pattern seems good. I was referring to other posts where you were suggesting the definition included the from and to URLs in one go. |
But, even better: @media (navigation-from: search-results) and (navigation-to: gallery) {
} Now you only need to define "search-results" URLs once, rather than twice. Given the argument for this pattern was because the repetition of URLs is brittle, it seems right to cut out the repetition completely. |
I still prefer
|
One important benefit of solving this early is that it gives us "events" out of the box, by registering to media query |
Ok, but please talk to the CSSWG and CSS-knowledgeable folks about it. For width, media queries use |
Naturally we'll discuss it at the WG. But anyway, I think the syntax conversation is more of a detail, and the bigger discussion is the relationship between a view-transition and a navigation. I feel that we should have a strategy around it, even if we don't implement everything in the first go. In #8677 we defined that one of the goals is that SPA & MPA don't diverge more than necessarry. In the MPA case, every transition is a navigation, so does that mean that (document-scoped) SPA transitions should also be navigation-oriented? In a way, because document-scoped view transitions block rendering for the entire page, they feel "navigation-y" even if they don't change the URL. The problem with treating every transition as a "navigation" is that soft navigations are not a well defined term and don't have a specified lifecycle but rather a concept that described multiple JS operations (see #8300), and the navigation API which attempts to define these terms is still experimental. I see several directions we could go with this:
Doing (1) is the easiest but might lead to footguns/antipatterns, and potentially a lot of over-capturing. It's perhaps a risk we can take and mitigate it with a lot of documentation/education, and making sure frameworks do the right thing. OTOH, I think that (2) could be feasible with the right naming choices. A big plus for (2) is that it gives us the JS events "for free" by using MediaQuery I'm currently into researching (4). Would love to have more opinions here... @tabatkins, @khushalsagar? |
Picking out only a detail from earlier in this thread: @navigation prev-slide {
target: urlpattern(/slide1);
type: navigate, back-forward;
}
@navigation next-slide {
target: urlpattern(/slide3);
type: navigate, back-forward;
} As an author, that would mean I need to write extra CSS for each and every page that my website holds. A snippet for page 1, page 2, page 3, …, page N. While this is easily possible to generate when using an SPA or some server side scripting language, not all sites have a build step and can just be static HTML. Ideally, to me, there’d be some way to flag the directionality from within the markup as well, or at least have a way to provide a clue from the markup to the CSS. One of the earlier ideas floated (in some other thread that I can’t find back) was to expose the navigation initiator somehow. For example, if the CSS somehow knew the users clicked |
I wouldn't use the link for this, perhaps you have both a "back" and a "jump to slide 2"? |
Proposing a syntax for matching one or more "navigations" as being the current ones, to be matchable in media-queries (and later other places).
A lot of the issues with view-transitions, especially cross-document, are around using different transitions based on different characteristics of the navigation:
#8784 (different transition for reload)
#8685 (different transition for back/forward)
#8683 (different transition for page type, e.g. home->article vs. articles->article)
#8209 (list<->details)
#8048 (opt-in for cross-document transitions)
These issues circle around some sort of url pattern matching, but adding url patterns to media queries seems verbose and might create duplications.
The proposal here is to use a @ rule that names a navigation-matcher, and then use it in media queries. For example:
In the spirit of #8677 (keeping MPA/SPA APIs compatible), the concept of navigation-matching here is not specific to MPAs.
A navigation always has an "old" and "new" URL, and a type. The current navigation is updated in the following scenarios:
a
element is clicked, the current URL at the time of clicking is the old URL, and thehref
is the new URL. This creates a referable point in time for "same-document navigations", which are not a defined term.popstate
event is fired, and the new one is the new URL.Notes:
a
pseudo-class that matches a particular link with the current navigation or so, see [css-view-transitions-2] CSS only way to transition between list <-> detail views #8209 (comment)<a href>
clicks is a common one but not the only one. This is OK though, this functionality is completely reproducible in JS - the same-document<a href>
behavior is a nice default that aligns with the cross-document behavior.The text was updated successfully, but these errors were encountered: