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

[css-view-transitions-2] Syntax for navigation-matching #8925

Open
noamr opened this issue Jun 6, 2023 · 30 comments
Open

[css-view-transitions-2] Syntax for navigation-matching #8925

noamr opened this issue Jun 6, 2023 · 30 comments
Labels
css-view-transitions-2 View Transitions; New feature requests

Comments

@noamr
Copy link
Collaborator

noamr commented Jun 6, 2023

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:

@navigation to-article {
   match: urlpattern(/article);
   type: navigation back-forward;
   direction: outgoing;  
}

@media (navigation: to-article) {
   a.article { view-transition: hero };
}

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:

  • When a document is activated, the previous active document's URL is the old URL and the active document's URL is the new URL.
  • When an a element is clicked, the current URL at the time of clicking is the old URL, and the href is the new URL. This creates a referable point in time for "same-document navigations", which are not a defined term.
  • When popping the state (same-document back/forward), the old document is the one right before the popstate event is fired, and the new one is the new URL.
  • Type is navigation/back-forward/reload, which maps to the existing "navigation timing type" concept

Notes:

  • Exposing previous URLs in this scenarios should adhere by referrer-policy and any other policy. i.e. CSS should only know about the previous cross-origin URL only if that information is also available in other means.
  • Several navigation matchers can match the current navigation at the same time, e.g. with wildcard URL patterns.
  • This makes it possible to customize when cross-document transitions are enabled, e.g.
@auto-view-transitions: same-origin; // bikeshedding the opt-in, see #8048
@media (navigation: to-article) {
@auto-view-transitions: none;
}
@noamr noamr added the css-view-transitions-2 View Transitions; New feature requests label Jun 6, 2023
@noamr
Copy link
Collaborator Author

noamr commented Jun 6, 2023

/cc @khushalsagar @tabatkins

@jakearchibald
Copy link
Contributor

jakearchibald commented Jun 8, 2023

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?

@noamr
Copy link
Collaborator Author

noamr commented Jun 8, 2023

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!
Something like the following:

// 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.
If we ever want to support declarative SPA transitions we can allow separating to from/to, we can also consider doing this now.

@jakearchibald
Copy link
Contributor

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?

@jakearchibald
Copy link
Contributor

What's the benefit in separating navigate and back-forward? When would you want to do something different when traversing forward between two pages, or a navigation between two pages?

@noamr
Copy link
Collaborator Author

noamr commented Jun 8, 2023

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.

Sure, need to play with it with a class-based polyfill, hard to whiteboard the exact thing.

I'm still not sure how I'd use this in an SPA. How would I activate these rules in an SPA?

   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>
     </>
   }
  • When you're on /slide1 and clicking <a href="/slide2">, the "current navigation" would match /slide1 (incoming) and /slide2 (outgoing).
  • You capture the old state, and later the router or whatever would eventually render the above JSX and would change the style and apply the new navigation matchers
  • At that point from-prev-slide navigation would be matched and its corresponding animation name (which you don't have to rerender).
  • Note that if you go back, from-prev-slide would be matched again but it would be unmatched when you re-render and won't apply to the pseudo-elements.

@noamr
Copy link
Collaborator Author

noamr commented Jun 8, 2023

What's the benefit in separating navigate and back-forward? When would you want to do something different when traversing forward between two pages, or a navigation between two pages?

Probably in most cases you won't, so navigation, back-forward would likely be the default, and you can change to navigation if you don't want history traversals to trigger the animation. I can imagine that in some cases the transition would signify something "new" and you wouldn't want to repeat it. What was the use case for you for opening #8685 btw?

I think one of the main use-cases for the navigation-type is actually to enable/disable animation on reload (#8784).

@jakearchibald
Copy link
Contributor

jakearchibald commented Jun 8, 2023

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 oldURL and newURL would activate the various media queries for the transition.

And that's a full example, and it didn't need frameworks, generated CSS etc etc.

@jakearchibald
Copy link
Contributor

What was the use case for you for opening #8685 btw?

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 one of the main use-cases for the navigation-type is actually to enable/disable animation on reload (#8784).

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.

@noamr
Copy link
Collaborator Author

noamr commented Jun 8, 2023

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 oldURL and newURL would activate the various media queries for the transition.

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 startVT function, sure, why not. I was thinking of something that would be declarative in advance, but putting this directly in startVT makes sense since it let's the SPA framework define what a navigation is.

@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.

@noamr
Copy link
Collaborator Author

noamr commented Jun 8, 2023

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.
Note also that URL patterns can be quite long and bulky, with RegEx etc.

So by putting them in their own rule we can achieve several things:

  • The author can put the routes themselves in one place, and the rules that correspond to them all over the place.
  • The rules can be extended without cluttering media-queries even more.

The other parts of this proposal are perhaps what makes it seem complicated for the slides case:

  • Automatic navigation-matching on link clicks
  • Having only a "target" rather than from+to

I think I'm OK with keeping the rule but spelling-out the to/from both in the rule and in the startVT function (in the SPA case)

@jakearchibald
Copy link
Contributor

How do you disable reloads or give them a different animation in this example?

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.

It seems great when it's simple but when you want to tweak it you might end up with monstrous media-queries.

Can you give an example?

Also, this is VT-specific. By having this as "navigations", you could style other things based on where you're coming from.

Maybe? But, making it work badly for VT because of some unknown non-VT use-case seems bad.

Regarding having the URLs in the startVT function, sure, why not. I was thinking of something that would be declarative in advance, but putting this directly in startVT makes sense since it let's the SPA framework define what a navigation is.

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.

btw this is a push animation and not a slide animation.

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.

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.

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.

I think I'm OK with keeping the rule but spelling-out the to/from both in the rule and in the startVT function (in the SPA case)

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 startViewTransition, I urge you to avoid the functionName(bigCallback, options) pattern. I think there's a path forward here, but it's novel whatwg/webidl#1191

@noamr
Copy link
Collaborator Author

noamr commented Jun 8, 2023

@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);
});

@jakearchibald
Copy link
Contributor

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)

@noamr
Copy link
Collaborator Author

noamr commented Jun 8, 2023

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 popstate. But perhaps we could have something as reasonable defaults, e.g. if new URL defaults to document URL at time of capture-new and old URL defaults to URL at capture-old, we could do with passing only oldURL on popstate and have the rest "just work".

@jakearchibald
Copy link
Contributor

Yeah, that might be nice and forward-looking.

document.startViewTransition({
  urls,
  update() {
    // update DOM here
  }
});

Where urls can be:

  • undefined - default, don't do anything with the media queries
  • "auto" - pick up the URLs automatically
  • { old, new } - the URLs. If either are left undefined, then they're picked up automatically.

Maybe that's a bit of a weird API shape, since {} would be equivalent to "auto". But I like the idea.

@noamr
Copy link
Collaborator Author

noamr commented Jun 8, 2023

Yeah, that might be nice and forward-looking.

document.startViewTransition({
  urls,
  update() {
    // update DOM here
  }
});

Where urls can be:

  • undefined - default, don't do anything with the media queries
  • "auto" - pick up the URLs automatically
  • { old, new } - the URLs. If either are left undefined, then they're picked up automatically.

Maybe that's a bit of a weird API shape, since {} would be equivalent to "auto". But I like the idea.

In general I like the idea of callback | {callback, ...}.
I'm not sure we need undefined though. If you don't want to deal with URLs, don't define @navigation rules / media-queries.

@jakearchibald
Copy link
Contributor

I'm not sure we need undefined though. If you don't want to deal with URLs, don't define @navigation rules / media-queries.

Hmm, not all view transitions are "page" transitions. That's why I don't think the media queries should apply by default.

@khushalsagar
Copy link
Member

khushalsagar commented Jun 9, 2023

@jakearchibald before going into the exact syntax, I want to make sure we're all on the same page about the following:

  • Not allowing media queries on the old Document to depend on any state parsed from the new Document. So something like this on the old Document:
@media (vt-next-page: article) {
  /* … */
}

where article comes from the new Document makes the implementation quite complicated. It's more preferable to have a syntax where the old Document uses the target URL of the navigation to avoid this dependency.

  • Extending this approach to SPA transitions:
    • It's better if we can enable these queries for same-document navigations, irrespective of whether there is a transition. We'll need to think through the lifetime of the queries with respect to the navigation lifecycle but I don't see the advantage of limiting it to navigations which have a ViewTransition (unless constrained by implementation).

    • On the flip side, if the transition is not associated with a navigation, then does it make sense to enable these queries? They would be tightly coupled with navigation concepts. We could have the author specify parameters that identify a navigation (url, type) in the call to startViewTransition but then it becomes ambiguous which state should we be using for these queries. For example, does the vt-old-page value come from the previous navigation entry's url or what the author passed in the startViewTransition call?
      We can have a think about this more but are there use-cases where an author would want this functionality but doesn't want to trigger a same-document navigation?

@noamr
Copy link
Collaborator Author

noamr commented Jun 10, 2023

@jakearchibald before going into the exact syntax, I want to make sure we're all on the same page about the following:

  • Not allowing media queries on the old Document to depend on any state parsed from the new Document. So something like this on the old Document:

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.

  • Extending this approach to SPA transitions:

    • It's better if we can enable these queries for same-document navigations, irrespective of whether there is a transition. We'll need to think through the lifetime of the queries with respect to the navigation lifecycle but I don't see the advantage of limiting it to navigations which have a ViewTransition (unless constrained by implementation).
    • On the flip side, if the transition is not associated with a navigation, then does it make sense to enable these queries? They would be tightly coupled with navigation concepts. We could have the author specify parameters that identify a navigation (url, type) in the call to startViewTransition but then it becomes ambiguous which state should we be using for these queries. For example, does the vt-old-page value come from the previous navigation entry's url or what the author passed in the startViewTransition call?
      We can have a think about this more but are there use-cases where an author would want this functionality but doesn't want to trigger a same-document navigation?

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"]})

@jakearchibald
Copy link
Contributor

jakearchibald commented Jun 12, 2023

@khushalsagar

  • Not allowing media queries on the old Document to depend on any state parsed from the new Document.

Yeah, I understand the technical limitations around this.

  • It's better if we can enable these queries for same-document navigations, irrespective of whether there is a transition. We'll need to think through the lifetime of the queries with respect to the navigation lifecycle but I don't see the advantage of limiting it to navigations which have a ViewTransition (unless constrained by implementation).

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:

  • Could there be cases where a cross-document transition should be reused in an SPA, but in the SPA it doesn't really make sense as a navigation? In this case we'd be forcing the developer to create a dummy navigation just to activate these rules.
  • Being able to control when the URL changes in an SPA navigation is currently an experimental feature in the navigation API. It isn't possible with the history API as the process is synchronous. Since this is limited to the navigation API, uptake in routing libraries might be slow.
  • Could this result in developers changing the URL at a sub-optimal point because it's what the view transition needs?

@noamr

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)

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 document.startViewTransition.

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"]})

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:

  1. index-to-index
  2. index-to-article
  3. index-to-gallery
  4. index-to-search-results
  5. article-to-index
  6. article-to-article
  7. article-to-gallery
  8. article-to-search-results
  9. gallery-to-index
  10. gallery-to-article
  11. gallery-to-gallery
  12. gallery-to-search-results
  13. search-results-to-index
  14. search-results-to-article
  15. search-results-to-gallery
  16. search-results-to-search-results

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.

@noamr
Copy link
Collaborator Author

noamr commented Jun 12, 2023

@khushalsagar

  • Not allowing media queries on the old Document to depend on any state parsed from the new Document.

Yeah, I understand the technical limitations around this.

  • It's better if we can enable these queries for same-document navigations, irrespective of whether there is a transition. We'll need to think through the lifetime of the queries with respect to the navigation lifecycle but I don't see the advantage of limiting it to navigations which have a ViewTransition (unless constrained by implementation).

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:

  • Could there be cases where a cross-document transition should be reused in an SPA, but in the SPA it doesn't really make sense as a navigation? In this case we'd be forcing the developer to create a dummy navigation just to activate these rules.

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.

  • Being able to control when the URL changes in an SPA navigation is currently an experimental feature in the navigation API. It isn't possible with the history API as the process is synchronous. Since this is limited to the navigation API, uptake in routing libraries might be slow.
  • Could this result in developers changing the URL at a sub-optimal point because it's what the view transition needs?

@noamr

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.

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)

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 document.startViewTransition.

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.

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"]})

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:

  1. index-to-index
  2. index-to-article
  3. index-to-gallery
  4. index-to-search-results
  5. article-to-index
  6. article-to-article
  7. article-to-gallery
  8. article-to-search-results
  9. gallery-to-index
  10. gallery-to-article
  11. gallery-to-gallery
  12. gallery-to-search-results
  13. search-results-to-index
  14. search-results-to-article
  15. search-results-to-gallery
  16. search-results-to-search-results

Unless I'm missing something, you'd end up declaring the same URL patterns 8 times each.

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.

@jakearchibald
Copy link
Contributor

@media (navigation: from-search-results) and (navigation: to-gallery) {
}

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.

@jakearchibald
Copy link
Contributor

jakearchibald commented Jun 12, 2023

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.

@noamr
Copy link
Collaborator Author

noamr commented Jun 13, 2023

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.

I still prefer (navigation: from search-results) and also allow (navigation: search-results) if it's bidirectional.
By having the direction optional/omitted by default, we make it easier to generate the simple case:

  • some view transitions only occur in specific navigations (e.g. list->movie + movie->list), also on "back" navigations.
  • the transition is the default, i.e. using the captured transform rather than a special keyframes.
  • Customizing by direction is possible and easy but not required

@noamr
Copy link
Collaborator Author

noamr commented Jun 13, 2023

One important benefit of solving this early is that it gives us "events" out of the box, by registering to media query change events.

@jakearchibald
Copy link
Contributor

I still prefer (navigation: from search-results)

Ok, but please talk to the CSSWG and CSS-knowledgeable folks about it.

For width, media queries use (min-width: value), not (width: min value), so make sure you have a good justification for breaking existing patterns.

@noamr
Copy link
Collaborator Author

noamr commented Jun 14, 2023

I still prefer (navigation: from search-results)

Ok, but please talk to the CSSWG and CSS-knowledgeable folks about it.

For width, media queries use (min-width: value), not (width: min value), so make sure you have a good justification for breaking existing patterns.

Naturally we'll discuss it at the WG.
Given 10px <= width <= 100px. I don't think we HAVE to limit ourselves to (key: value).

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:

  1. leave this to userland JS, see what patterns emerge. Experiment with polyfills for this with e.g. the navigation API or something like this. Note that almost everyone using view-transitions for navigations would have to use a polyfill similar to this, or count on the routing framework (Next etc) to include that functionality.

  2. Give names to transitions/navigations, allow to declaratively link them with navigations in the MPA case, and specify them explicitly in the SPA case (some version of this. Think about making this declarative for SPA when we get to [css-view-transitions-2] Declarative view transitions for same-document navigations. #8300.

  3. Specify an initial version [css-view-transitions-2] Declarative view transitions for same-document navigations. #8300 now. In a way, an app that supports both SPA and MPA does have a pattern: capturing link clicks and popstate in the SPA case and not capturing them in MPA. But this might be a bit leaky until we resolve some things around the navigation API.

  4. Integrate those media queries with the navigation API. As in, only when the "well lit path" of navigating via the navigation API is followed, we trigger the navigation matchers.

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 change events.

I'm currently into researching (4).

Would love to have more opinions here... @tabatkins, @khushalsagar?

@bramus
Copy link
Contributor

bramus commented Jun 14, 2023

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 a#previous-page to start the navigation, it could use that info to determine that it’s a backwards type of animation that needs to be done.

@noamr
Copy link
Collaborator Author

noamr commented Jun 14, 2023

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 a#previous-page to start the navigation, it could use that info to determine that it’s a backwards type of animation that needs to be done.

I wouldn't use the link for this, perhaps you have both a "back" and a "jump to slide 2"?
If we really wanted to support this use case in the web platform I would do something like define an order between the pages when declaring them and use that as an extra semantic in the media-queries. But I think this might be too niche, specifically for slideshow-style things, and perhaps it's easy enough to generate this from SCSS/some server framework?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
css-view-transitions-2 View Transitions; New feature requests
Projects
None yet
Development

No branches or pull requests

4 participants