w3c / csswg-drafts

CSS Working Group Editor Drafts
https://drafts.csswg.org/
Other
4.42k stars 647 forks source link

[css-view-transitions-2] Declarative opt-in for cross-document navigations #8048

Closed jakearchibald closed 10 months ago

jakearchibald commented 1 year ago

Cross-document transitions need some way for both the old & new page to opt-in to a transition.

The SPA API uses JS for this, but it would be nice if cross-document transitions didn't depend on JS.

It feels like this should be in CSS, so it can be influenced by media queries, particularly prefers-reduced-motion.

The tricky part here is it's a "global" setting, so it can't be a CSS property.

Proposal:

@cross-document-transition allow;

@media (prefers-reduced-motion) {
  @cross-document-transition deny;
}

However, I'm just making stuff up here. Is there any prior art here for setting 'global' things?

khushalsagar commented 1 year ago

I find this syntax is very confusing. It looks like state is added, yet the descriptors inside it apply when the state is no longer active?

In terms of the duration for when the "reload" state is activated in CSS, that'll be the same irrespective of whether its a media-query or pseudo-class. Can you elaborate why you find the use of pseudo-class more confusing?

tabatkins commented 1 year ago

It seems a little strange for reloads, specifically, to be handled differently than other trigger qualities; it seems to be just as much a quality of the trigger as "same-origin" vs "cross-origin", I think? I suggest baking this into the trigger syntax itself, and using comma separation, like:

@view-transition {
  transition-trigger: none | [ [ reload | no-reload ] || <transition-type> ]#;
}
vmpstr commented 1 year ago

@view-transition { transition-trigger: none | [ [ reload | no-reload ] || ]#; }

Is this different from just having a "reload" keyword, since the default and "no-reload" would prumably have the same behavior

css-meeting-bot commented 1 year ago

The CSS Working Group just discussed Declarative Cross-document View Transitions.

The full IRC log of that discussion <fantasai> Topic: Declarative Cross-document View Transitions
<fantasai> github: https://github.com/w3c/csswg-drafts/issues/8048
<fantasai> khush: Last time discussed lots of good feedback.
<fantasai> khush: main issue is figuring out declarative feedback for doing cross-document navigation transitoins
<fantasai> khush: Sub-cases are same-origin vs same-site navigation
<fantasai> khush: Same-document it's just syntactic sugar, can do via JS API in L1
<fantasai> khush: but nice to have
<fantasai> khush: First, if we go for simplest opt-in, binary yes/no allow/disallow
<fantasai> khush: but a bunch of cases have different parameters, and authors may want to decide opt-in based on what navigation corresponds
<fantasai> khush: additionally there are some parameters to decide what transition looks like
<fantasai> khush: i.e. what elements animate independently, or how to style the animation
<fantasai> khush: same-document / cross-document / same-origin / same-site
<fantasai> khush: You call document.startViewTransition, generally that should be op-tin
<fantasai> khush: but we found some cases where someone might wnat to disable transitions for prefers-reduced-motion
<fantasai> khush: and declarative syntax makes this easy
<fantasai> khush: For navigation, might want different animation depending on type of navigation
<fantasai> khush: e.g. forward vs back
<fantasai> khush: [missed]
<fantasai> khush: Lastly, which page are you going to.
<fantasai> khush: e.g. clicked item in the list, decides UI of next page, want to customize based on that
<fantasai> khush: From all these cases, if there are some which are mutually exclusive, only thing that needs to impact opt-in
<vmpstr> s/[missed]/there's also replace navigation, and push navigation/
<fantasai> khush: wouldn't change opt-in depending on same-document vs cross-document, don't need to change if the DOM looks the same
<fantasai> khush: In that case, have it be opt-in
<Rossen_> q?
<fantasai> khush: but if based on that you want to customize transition, e.g. back vs forward, change direction that content slides
<noamr> q+
<fantasai> khush: let's make that something that can be used to customize all CSS, not just this opt in
<fantasai> khush: I thought at first to use an @media query
<fantasai> khush: noam proposed using pseudo-classes instead
<fantasai> khush: and there's precedent for doing this with @page at-rule
<fantasai> khush: Right now 3 proposal
<fantasai> khush: 1. Use @media queries for deciding navigation back/forth/specific URL
<emilio> q+
<SebastianZ> q+
<fantasai> khush: also whether initiated via script, etc. All these cases are expressed as tokens in the opt-in rules
<fantasai> khush: @view-transition takes a parameter, 'transition-trigger', and you can specify various tokens for allowing
<fantasai> khush: Previously we discussed having reloads disabled by default, but with this syntax it's hard
<fantasai> khush: It seems to imply reload
<Rossen_> q?
<fantasai> khush: Second tries to solve that by saying that we can add another parameter to the at-rule, which is just 'reload', allow/disallow; initial value can be disallow
<fantasai> khush: only reason to do this is that media queries, they don't add any specificity, so can't add a UA style rule that says "don't trigger for reload"
<fantasai> khush: Later on, one suggestion from SebastianZ to include reload token within the 'transition-trigger' list itself
<TabAtkins> Wait, can't you tho? We don't need specificity, just order of appearance, right?
<fantasai> khush: technically not mutually exclusive, because same-origin or cross-document is [missed]
<TabAtkins> Ah tho if the author turned on some navigations that would override the "not on reload" rule then
<vmpstr> any author opt-in would override the reload "opt-out"
<vmpstr> yeah exactly
<fantasai> khush: but we're not aware of use cases where people would want to do differently for cross-document vs same-document reload
<fantasai> khush: Last option was using pseudo-class, use @view-transition but you can add a pseudo-class which is a mapping to the navigation type
<fantasai> khush: then we can add a UA style rule @view-transition :reload { [no transition] }
<Rossen_> q?
<fantasai> khush: It will have more specificity, so UA rule would win
<fantasai> khush: Because of that I'm liking this option the most
<Rossen_> ack noamr
<fantasai> noamr: Want to add that this conversation came from F2F where we were asked to think ahead to features we wanted in View Transitions
<fantasai> noamr: even though all we want to do in L2 is the simple opt-in
<TabAtkins> hmmm, i might suggest making the property comma-separated, one keyword per - then you can add additional features (like reload) to each iteration.
<fantasai> noamr: idea that we think ahead to how things look like
<fantasai> noamr: In all those options, the first version is very similar
<fantasai> noamr: where we have a view transition rule and inside of it a navigation trigger etc.
<TabAtkins> trans-trigger: none | [ [reload | no-reload] || <transition-type> ]#
<Rossen_> ack emilio
<fantasai> emilio: I wanted to mention that media queries seem like an odd choice here
<fantasai> emilio: feels cleaner to just extend the rule to allow selecting the cases you want
<fantasai> emilio: Media queries you can do anything inside them, not just view transition rules
<fantasai> emilio: so unclear when that applies
<fantasai> emilio: do we need to do a full style update?
<TabAtkins> Bringing in specificity for the rule itself seems a little more complex than we need, and it seems strange to promote reload, specifically, to be the thing promoted to "selector"-ish.
<fantasai> emilio: so it feels like an odd choice, so if we ned to add this kind of selector capability, extending the rule itself seems better
<TabAtkins> q+
<fantasai> emilio: Other thing to mention, we have a kind of precedence for this kind of stuff with scroll-behavior
<fantasai> emilio: it was mentioned that what you want to do is e.g. disable imperative animations
<fantasai> emilio: stylesheet would override
<fantasai> emilio: that's not how scrollIntoView etc works
<fantasai> emilio: so might want to be consistent with that
<Rossen_> ack SebastianZ
<fantasai> SebastianZ: Noam pointed out important thing, this is divided into 3 pieces
<fantasai> SebastianZ: URL, type, and mechanism
<fantasai> SebastianZ: was thinking about, maybe they shouldn't be part of the prelude but rather different descriptors
<noamr> q+
<fantasai> SebastianZ: so have a descriptor for each of these pieces
<khush> q+
<fantasai> SebastianZ: so you'd have a type descriptor that takes "reload | travers | etc"
<fantasai> SebastianZ: a descriptor for same-origin / cross-origin
<fantasai> SebastianZ: and a descriptor for the mechanism itself
<Rossen_> ack fantasai
<Zakim> fantasai, you wanted to clarify that origin wins over specificity
<fantasai> scribe+ emilio
<emilio> fantasai: Wanted to point out that in the cascade, origin is more powerful than specificity
<emilio> ... so even if specificity of the :reload pseudo-class is higher UA origin would override
<emilio> ... I also want to agree with emilio wrt stashing this on a media query
<TabAtkins> q-
<TabAtkins> actually i'm gonna just take my convo to the issue
<emilio> ... SebastianZ's idea of encapsulating all these in descriptors makes sense, it's like @font-face
<emilio> ... the other thing authors might want to control is defining the type of navigation based on the URL
<emilio> ... and you might want to have that centralized
<Rossen_> q?
<emilio> ... that way when you need to update any of these types of navigations you don't need to go through everything
<fantasai> s/everything/everything to update the URL list everywhere/
<fantasai> ... I think it would be useful to style based on the class of view transition (author-defined class)
<fantasai> noamr: Idea of having descriptor for transition class or group, equivalent to how we would do it in SDA, like a parameter to .startViewTransition
<emilio> s/SDA/SPA
<fantasai> noamr: in this case, we can't have other descriptors for URL origin for navigation type
<fantasai> noamr: because they would interfere with each other
<fantasai> noamr: that's why I want outside the braces, as part of pseudo-classes
<fantasai> noamr: If this is a back navigation, use this transition
<fantasai> noamr: if it is a ???, then don't allow cross-origin
<fantasai> noamr: It needs to be outside so we can style navigations based on it
<fantasai> noamr: so what's outside is the navigation type and origin, and inside is only the mechanism
<fantasai> noamr: something that shouldn't affect the styling, but only be a trigger boolean opt in
<Rossen_> ack noamr
<Rossen_> ack khush
<fantasai> khush: Question for fantasai and emilio
<fantasai> khush: You mentioned you don't like idea of media query or pseudo-class
<fantasai> khush: but if I want to add a view transition class name based on what type of transition it is
<fantasai> khush: how would I go about doing that?
<fantasai> khush: either can specify any CSS rule, or ...
<fantasai> khush: any suggestion other than MQ or pseudo-class? How would they specify different `view-transition-name`?
<fantasai> <fantasai> Good question... I don't have a good answer.
<fantasai> Rossen_: Doesn't seem we're ready for resolution, but getting some sense of direction
<fantasai> Rossen_: Seems like it should continue in the issue
<fantasai> khush: Can take to issue
<fantasai> khush: What I'm stuck on is what CSS concept to use on customization
<fantasai> khush: If someone could put some thoughts, that would help move the issue forward
<khush> Thank you!
noamr commented 1 year ago

It seems a little strange for reloads, specifically, to be handled differently than other trigger qualities; it seems to be just as much a quality of the trigger as "same-origin" vs "cross-origin", I think? I suggest baking this into the trigger syntax itself, and using comma separation, like:

@view-transition {
  transition-trigger: none | [ [ reload | no-reload ] || <transition-type> ]#;
}

It's a different quality from same-document/cross-document, as reload could be either. Also, a reload is something that might call for a different customization (class/group), e.g.:

@view-transition :reload {
  navigation-trigger: cross-document-same-origin;
  /* this would be available in MQs to customize the transition */
  transition-group-name: reloading;
}
vmpstr commented 1 year ago

Re: media query and importantly having the ability to add general css in those blocks (to add/remove view-transition-name on elements), does it make sense to have a @navigation (instead of @media) for this to gate based on navigation type

Eg,

.foo {
 view-transition-name: foo
}
@navigation reload {
.foo {
  view-transition-name: none
}
}

Or something along those lines? Or is the objection to the media-query style proposal extend to any at-rule style syntax?

Also, presumably @view-transition opt-in block can also be wrapped in the @navigation block

noamr commented 1 year ago

Re: media query and importantly having the ability to add general css in those blocks (to add/remove view-transition-name on elements), does it make sense to have a @navigation (instead of @media) for this to gate based on navigation type

Eg,

.foo {
 view-transition-name: foo
}
@navigation reload {
.foo {
  view-transition-name: none
}
}

Or something along those lines? Or is the objection to the media-query style proposal extend to any at-rule style syntax?

Also, presumably @view-transition opt-in block can also be wrapped in the @navigation block

Think of two things:

  1. composition
  2. compatibility with SPA
    
    @view-transition :reload {
    navigation-trigger: cross-document;
    view-transition-group: refreshing;
    }

@media (view-transition-group: refreshing) and (prefers-reduce-motion: no-preference) { }


```js
function refreshView() {
  startViewTransition({ groupName: "refreshing", update: async () => { ... });
}

Also having it as an MQ gives us the MQ javascript API for free. I don't see what a new @ rule adds when it acts exactly like a media query.

SebastianZ commented 1 year ago

As I understand it, the point of the @view-transition rule as it was initially proposed is to configure under which conditions view transitions should be triggered.

It does not cover different view transitions based on those conditions. If there should be different transitions for different conditions, we need a separate feature to detect that.

New media features lend themselves to target this use case. Though if we go that route, I'd suggest to keep them general and only bind them to navigation, not view transitions specifically.

So we'd introduce media features like navigation-type: [ reload | push | replace | traverse ], navigation-origin: [ same-origin | cross-origin ] (plus maybe URL patterns) and navigation-mechanism: [ interaction | api ].

So a media query could then look like this:

@media (navigation-type: reload) or (navigation-origin: cross-origin) {
  …
}

Sebastian

noamr commented 1 year ago

It seems a little strange for reloads, specifically, to be handled differently than other trigger qualities; it seems to be just as much a quality of the trigger as "same-origin" vs "cross-origin", I think? I suggest baking this into the trigger syntax itself, and using comma separation, like:

@view-transition {
  transition-trigger: none | [ [ reload | no-reload ] || <transition-type> ]#;
}

On second thought, thinking of what @fantasai brought up about specificity, I think perhaps we should go with reload (but not back-forward) in the opt-in. It means we can't customize the transition based on whether this is a reload, but at least it makes the whole specificity thing a lot simpler and perhaps customizing based on reload/not-reload is not an important use-case to begin with.

khushalsagar commented 1 year ago

As I understand it, the point of the @view-transition rule as it was initially proposed is to configure under which conditions view transitions should be triggered. It does not cover different view transitions based on those conditions. If there should be different transitions for different conditions, we need a separate feature to detect that.

Thanks for the feedback @SebastianZ. +1, the point of @view-transition rule is indeed to configure which conditions view transitions should be triggered for. We inevitably end up talking about view transition customization (what the animation looks like) here to ensure it works well with the rule. reload is especially tricky because we want transitions to be disabled-by-default for them and also allow authors to customize the transition for this case.

New media features lend themselves to target this use case. Though if we go that route, I'd suggest to keep them general and only bind them to navigation, not view transitions specifically.

Huge +1 to this. Navigation related media feature shouldn't be limited to view transitions. They are a general concept which VT need as a building block since we need to enable authors to use different CSS based on the ongoing navigation.

So we'd introduce media features like navigation-type: [ reload | push | replace | traverse ], navigation-origin: [ same-origin | cross-origin ] (plus maybe URL patterns) and navigation-mechanism: [ interaction | api ].

Our thinking was to limit media features to cases which need to customize the transition, and for now we've only seen use-cases for navigation-type. Were you proposing that every aspect of the navigation (same-document vs cross-document, same-origin vs cross-origin) should be a media feature? As opposed to part of the opt-in at-rule.

khushalsagar commented 1 year ago

@noamr, regarding the syntax below:

@view-transition :reload {
  navigation-trigger: cross-document;
  view-transition-group: refreshing;
}

@media (view-transition-group: refreshing) and (prefers-reduce-motion: no-preference) {
}

I'm not seeing the advantage of having an indirection, where :reload is available on @view-transition to set a view-transition-group and then the group is available as a media-query. Why not use reload directly in the media-query like in @SebastianZ's example. I tend to agree that if we're introducing a CSS syntax for navigation state, there is no reason to tie it to View Transitions.

noamr commented 1 year ago

@noamr, regarding the syntax below:


@view-transition :reload {

  navigation-trigger: cross-document;

  view-transition-group: refreshing;

}

@media (view-transition-group: refreshing) and (prefers-reduce-motion: no-preference) {

}

I'm not seeing the advantage of having an indirection, where :reload is available on @view-transition to set a view-transition-group and then the group is available as a media-query. Why not use reload directly in the media-query like in @SebastianZ's example. I tend to agree that if we're introducing a CSS syntax for navigation state, there is no reason to tie it to View Transitions.

The indirection is there to support non-navigation SPA (startViewTransition({groupName: "refreshing"}). Otherwise you'd have to bring all this jazz into startViewTransition or make it very coupled with the navigation API

noamr commented 1 year ago

As I understand it, the point of the @view-transition rule as it was initially proposed is to configure under which conditions view transitions should be triggered.

It does not cover different view transitions based on those conditions. If there should be different transitions for different conditions, we need a separate feature to detect that.

Thanks for the feedback @SebastianZ. +1, the point of @view-transition rule is indeed to configure which conditions view transitions should be triggered for. We inevitably end up talking about view transition customization (what the animation looks like) here to ensure it works well with the rule. reload is especially tricky because we want transitions to be disabled-by-default for them and also allow authors to customize the transition for this case.

New media features lend themselves to target this use case. Though if we go that route, I'd suggest to keep them general and only bind them to navigation, not view transitions specifically.

Huge +1 to this. Navigation related media feature shouldn't be limited to view transitions. They are a general concept which VT need as a building block since we need to enable authors to use different CSS based on the ongoing navigation.

How would you use navigation media queries outside of VT? And considering that grouping would also be done with VT, this would create a strange situation where you have to compute media queries twice.

I am afraid we might have to resolve transition groups and see the whole picture before we come to a conclusion here.

So we'd introduce media features like navigation-type: [ reload | push | replace | traverse ], navigation-origin: [ same-origin | cross-origin ] (plus maybe URL patterns) and navigation-mechanism: [ interaction | api ].

Our thinking was to limit media features to cases which need to customize the transition, and for now we've only seen use-cases for navigation-type. Were you proposing that every aspect of the navigation (same-document vs cross-document, same-origin vs cross-origin) should be a media feature? As opposed to part of the opt-in at-rule.

SebastianZ commented 1 year ago

New media features lend themselves to target this use case. Though if we go that route, I'd suggest to keep them general and only bind them to navigation, not view transitions specifically.

Huge +1 to this. Navigation related media feature shouldn't be limited to view transitions. They are a general concept which VT need as a building block since we need to enable authors to use different CSS based on the ongoing navigation.

How would you use navigation media queries outside of VT? And considering that grouping would also be done with VT, this would create a strange situation where you have to compute media queries twice.

My reason was that media features refer to some specific feature of the user agent, the display device or a user preference. They generally don't refer to a some specific thing defined in CSS.

The indirection is there to support non-navigation SPA (startViewTransition({groupName: "refreshing"}). Otherwise you'd have to bring all this jazz into startViewTransition or make it very coupled with the navigation API

The question is, what are the use cases for SPAs that aren't covered by the existing features?

E.g. reduced motion preferences can be handled like this using the API:

if (!matchMedia('(prefers-reduced-motion)').matches) {
  document.startViewTransition(…);
}

Sebastian

vmpstr commented 1 year ago

I think the idea is that if you have

@media (view-transition-group: refreshing) and (prefers-reduce-motion: no-preference) {
}

then either startViewTransition(type: "refreshing") or @view-transition :reload { view-transition-group: refreshing } can trigger that media query.

I'm not convinced that this is a strong reason to avoid having a specific @media (navigation-type: reload) though, because you can likely combine that with view-transition-group that would only come from script.

I do see the advantage of @media (navigation-type: foo) as compared to @navigation foo since you can compose the former with other media queries

bramus commented 1 year ago

I do see the advantage of @media (navigation-type: foo) as compared to @navigation foo since you can compose the former with other media queries

One reason to prefer @navigation over @media could be to limit what is allowed inside of the block. When using @media, an author can put just about anything in there, and thus conditionally style the page based on the navigation.

If this is not feasible because of whatever reason, then using @navigation could be a better way, as that could be designed to only accept certain types of nested rules.

A third option is to add these navigation conditions onto a dedicated @view-transition rule, narrowing the reach of it even more.

khushalsagar commented 1 year ago

One reason to prefer @navigation over @media could be to limit what is allowed inside of the block.

We can limit what's allowed inside the block either way. If you use the navigation: foo query then that @media block can activate whatever restrictions are necessary.

The question is, what are the use cases for SPAs that aren't covered by the existing features?

The SPA feature request is at https://github.com/w3c/csswg-drafts/issues/8960. Maybe @ydaniv can provide us the concrete details. I'd say this feature request can apply to cross-document (MPA) cases as well.

At a high level, the transition is from/to a UI state which has a semantic meaning and that's not always visible to the user agent. For example, you can say that if the page's URL is foo.html/home then its the home page. Providing some way to apply CSS based on the old/new Document's URL is enough to customize a transition from/to the home page. But the home page could have a different UI depending on whether the user is signed in. So we want some API for the author to provide a custom ident identifying a transition and then be able to use it in CSS to customize animations for that transition.

The indirection is there to support non-navigation SPA (startViewTransition({groupName: "refreshing"}). Otherwise you'd have to bring all this jazz into startViewTransition or make it very coupled with the navigation API

That's fine for cases that the user agent can't know about but it seems silly to force the authors to use the pattern below for known cases, instead of being able to use the foo qualifier directly in the media-query (or something else):

@view-transition :foo {
  navigation-trigger: cross-document;
  view-transition-group: foo;
}

@media (view-transition-group: foo) { ... }

I think the fundamental questions based on the discussion above (and in the meeting) we need to answer before diving into the exact syntax are:

  1. Authors need the capability to conditionally apply any CSS based on the type of navigation to support basic customization. Something like:

    @media (navigation: back) {
      #back-button { view-transition-name: back-button; }
    }

    This is being done in SPAs using script since the information is available via the navigate event. If we don't provide a CSS way, authors will have to use script. Also, while the navigate event makes it trivial to get this info on the old Document, there is no such event on the new Document. So authors will have to do hacks to pass along this information to the new Document somehow (link decoration, sessionStorage API, etc.).

    The options considered are media-queries, pseudo-class, a new @navigation at-rule. The problem for defining the lifetime of a particular navigation state in the style system is the same regardless of the syntax chosen.

  2. If we want reload to be default off, then there is no way to do that without including it within the opt-in at-rule based on the options being considered in 1. Since reloads are also a potential customization case, and should be one of the nav types in 1 above, ideal way would've been for UA CSS to make it off unless the author explicitly enables it for reloads.

So let's resolve on how we want to handle 1? Whether we want CSS to solve this and how; or recommend that authors use existing script hooks on the old Document and probably introduce a script hook on the new Document which provides that info. @domenic @fantasai for an opinion.

ydaniv commented 1 year ago

The SPA feature request is at https://github.com/w3c/csswg-drafts/issues/8960. Maybe @ydaniv can provide us the concrete details. I'd say this feature request can apply to cross-document (MPA) cases as well.

The request is to be able to style the VT's pseudo tree based on the state (type) of the transition. There are also concrete examples for setting view-transition-name's as well.

Using the pseudo-classes from https://github.com/w3c/csswg-drafts/issues/8960#issuecomment-1671986616 should cover the requests above. It's clear how to set them from script, so the only question is how to set them via style, which I think can be done via navigation/media rules.

noamr commented 11 months ago

Summarizing current thinking/proposal for the breakout + discussion.

The “opt-in” is in fact about defining a behavior: a navigation triggers a view transition. A declarative version of the following:

onNavigation(() => {
    if (someConditionsAreMet) {
document.startViewTransition(someParameters);
       }
});

When specifying the syntax of this we need to think about it extending in the following ways:

For parameters, this should be 1:1 mapped to what parameters startViewTransition can pass to a transition with #8960, this includes a set of idents (or some such) that classify which transition this is. If more parameters are added to startViewTransition, they should also be added to the behavior declaration.

For environment conditions, this is well covered by media-queries.

For navigation conditions, the initial condition is to scope this behavior to same-origin navigations only, with a syntax that can extend later to conditions based on URLs and on navigation types (e.g. back/forward). At first, developers can achieve the more complex navigation-based customization using JS.

As discussed in the last F2F, the basis for this should be a new @ rule. To make it environment-aware, it should be possible to nest this rule inside media-queries.

Potential names for this rule could be @navigation or @view-transitions, or perhaps @auto-view-transitions or @page-transitions. The rule should include two descriptors:

Suggesting something like the following:

@navigation same-origin {
  view-transition-behavior: activate;
  view-transition-classnames: slide-in reverse;
}

Instead of @navigation, if this is too generic, we can call it something like @view-transitions or @page-transitions.

A few points about this:

In the future, this can include URLs and navigation-types, however we’re not proposing this yet. A possible syntax can look like this:

@navigation back from urlpattern(/home/*) {
  view-transition-behavior: trigger;
}

/* or with url patterns defined separately */
@routes { --home: urlpattern(/home/); }
@navigation back from --home {
  view-transition-behavior: trigger;
}

In essence a navigation is always qualified by URLs, navigation type, and phase (outgoing vs incoming).

Alternatives considered to URL pattern matching:

Points for discussion:

Currently out of scope:

css-meeting-bot commented 11 months ago

The CSS Working Group just discussed [css-view-transitions-2] Declarative opt-in for cross-document navigations, and agreed to the following:

The full IRC log of that discussion <noamr> https://github.com/w3c/csswg-drafts/issues/8048#issuecomment-1716035713
<TabAtkins> noamr: Same as previous, I posted a comment that summarized current thinking and has some HAQs
<TabAtkins> noamr: this is about cross-document VT
<TabAtkins> noamr: the way we look at this, it's a conditional dependency
<TabAtkins> noamr: An if() statement that's called twice, once when you leave the old doc, and once when you're ready to render the new doc
<TabAtkins> noamr: when this event happens we want to check the conditions are met
<TabAtkins> noamr: Some are environmental, like from MQ or supports, others are conditions about navigation itself
<TabAtkins> noamr: Sematnically this could mean "are we moving from 'play' page to 'song' page"
<TabAtkins> noamr: If conditions are met we want to start the VT, as if we were in JS. On the old page that means capturing the state of the old document and magically passing it along to the new one.
<TabAtkins> noamr: So on the new page if we successfully opted in, we start the VT with the stuff we captured from the old doc
<TabAtkins> noamr: And w'ell pass the transition types that we just talked about
<TabAtkins> noamr: So if going between a playlist and song page, this is an "expand" transition
<TabAtkins> noamr: So these are ways to declaratively map what VT is taking place
<TabAtkins> noamr: We're thinking of the whole thing as a transition behavior that's activated from a navigation
<TabAtkins> noamr: As we decided in last f2f we wanted a new at-rule
<TabAtkins> noamr: Currently called @navigation
<TabAtkins> noamr: First cross-document thing in CSS, exciting
<TabAtkins> noamr: Details all in the comment
<TabAtkins> noamr: We qualify the navigation in some way
<TabAtkins> noamr: Inside of it we ahve descriptors, like font descriptors.
<TabAtkins> noamr: view-transition-behavior, and which type names are passed along
<TabAtkins> noamr: There was a q from elika yesterday why we went with a name like "same-origin", or why it has to be urls
<TabAtkins> noamr: We really dug into this quite deep
<TabAtkins> noamr: The first proposal in this sapce was we parse both docs, and they each declare what type they are
<TabAtkins> noamr: Doc A could say it's "playlist" and doc b could say it's "song", but that's complicated, you have to know what the new page is before you can unload the old page, which is too hard to do right
<TabAtkins> noamr: Second option was controller based
<TabAtkins> noamr: To decide based on what link was clicked
<TabAtkins> noamr: Too limiting, sometimes you click the back button. Sometimes you want a transition from a `location.href` mutation
<TabAtkins> noamr: So clicking is too limiting
<TabAtkins> noamr: All we ahve left is URLs
<TabAtkins> noamr: They're the one thing we're guaranteed to have in cross-document navigation
<TabAtkins> noamr: So we qualify these by URLs, it's the only thing we can do as far as we can tell.
<TabAtkins> noamr: Reason why we put same-origin there by default is we dno't support cross-origin or same-site yet, for various reasons.
<TabAtkins> noamr: We wanted, for the reader, for it to be clear that this is a same-origin navigation. Later it's expandable to various things like urlpattern
<TabAtkins> noamr: Or qualifying with back/reload/etc navigation types
<TabAtkins> noamr: We were asked for what kinds of things we expect to see in the future
<TabAtkins> noamr: We expect same things that exist in Navigation API. Type, URL, and incoming/outgoing url
<TabAtkins> noamr: So anything that could go into startViewTransition() could go here
<TabAtkins> noamr: Names of types go into sVT(), so they go here. Future args also go here.
<TabAtkins> noamr: If we do anything like mixins it'll reflect here
<TabAtkins> (Unsure what is meant by "mixins" here but I dont' think it's important)
<TabAtkins> noamr: We also have something called "navigation" here, pretty general
<TabAtkins> noamr: We didn't think building into @supports or anything was appropriate
<TabAtkins> noamr: Also questions about and/or here
<TabAtkins> noamr: Okay to not resolve that yet, just general behavior.
<TabAtkins> noamr: If our vision of declarative nav transitions makes sense, even if we don't resolve on details now, just want to validate that the syntax is extendable in this way
<TabAtkins> astearns: Just as a scoping thing, I think it's great to look at future extensions of the syntax, so thanks for htat
<TabAtkins> astearns: All you're asking for resolution on for now is @navigation with those descriptors, and only same-origin?
<TabAtkins> noamr: Just the same-origin descriptor, and the vt class names that we just resolved on
<TabAtkins> noamr: For more behavior, we'll wait to resolve those generally
<eeeps> q+
<astearns> ack fantasai
<TabAtkins> fantasai: I think we do need to have a good sense of the whole package and decide this looks good in general
<zcorpan> q+
<TabAtkins> fantasai: Just don't want us to decide on something, ship it, and then it looks awkward or doesn't actually expand as we needed.
<TabAtkins> fantasai: So just want to make sure this is what we want to do
<TabAtkins> fantasai: I have concerns with urlpatterns. Generally we're opaque to what url you actually are.
<TabAtkins> fantasai: Some features where we're breaking that
<TabAtkins> fantasai: But for something like this, you need full regex to capture these
<noamr> q+
<TabAtkins> fantasai: Like for a blog, recognizing a date in the url, etc
<noamr> URL patterns contain regular expressions
<TabAtkins> fantasai: And that won't work for websites with random ids
<TabAtkins> fantasai: I understand th eproblems with pages defining their own classes; I don't have a great answer
<TabAtkins> astearns: Noam's response is that urlpatterns do contain regexes
<fantasai> TabAtkins: URL patterns are being developed elsewhere for a lot of other use cases, we just need a subet
<fantasai> TabAtkins: I think it's fine
<fantasai> TabAtkins: While I also agree it's probably a bit awkward, it seems like the best way forward afaict
<TabAtkins> astearns: And whether or not that's correct, I think we can shoehorn *something* that does this matching between URLs into this at-rule later
<fantasai> TabAtkins: current extensability plan in the comment seems reasonable
<astearns> ack eeeps
<TabAtkins> eeeps: Is there time to wait for *anything* from the second doc? Like an http header, or an early <meta>?
<TabAtkins> eeeps: Or is there just no way to keep the outgoing doc alive
<TabAtkins> noamr: We can keep it alive for a bit, and this can be a future extension to the rendering model
<TabAtkins> noamr: But we don't want to rely on it for how transitions are defined. It's kinda an advanced, complicated addition to the web platform.
<TabAtkins> noamr: It's like prerendering but more
<TabAtkins> noamr: So actually quite complicated to do right and cross-browser
<TabAtkins> noamr: So don't want to rely on it for now. Can be a future UX enhancement.
<TabAtkins> eeeps: So the incoming URL really is the only thing you can rely on from the incoming page, so far
<TabAtkins> noamr: correct
<TabAtkins> astearns: And this can be a future discussion since we're not resolving on that bit today
<astearns> ack zcorpan
<TabAtkins> zcorpan: syntax q about urlpattern
<TabAtkins> zcorpan: I think it's a string? URLs can conflict with CSS syntax.
<khush> q+
<fantasai> TabAtkins: absolutely. Never want to repeat the unqouted URL mistake again
<TabAtkins> TabAtkins: Oh yeah we're never repeating the "unquoted urls" problem again, I didn't notice that.
<astearns> ack noamr
<astearns> ack fantasai
<Zakim> fantasai, you wanted to comment on the classifying links idea
<TabAtkins> fantasai: you mentioned the idea of changing the transition based on which link you clicked. that sounds like something people might want
<TabAtkins> fantasai: would be something to consider, i guess would override this general routing
<TabAtkins> fantasai: Also, I think it would be more udnerstandable if this wasn't named generically "@navigation". Would be clearer what it's for, wouldn't have to repeat "view-transition" in each thing.
<TabAtkins> noamr: Yeah, qualifying a transition by the "controller" (link clicked) is osmething we lik ein general, it's just a different feature
<fantasai> and more clearly a separate namespace as e.g. 'view-transition-name'
<TabAtkins> noamr: So you can cusotmize by URL and by "last-active" link (Bramus' term)
<TabAtkins> noamr: I think those can be taken separately without conflict, we're on the sam epage
<TabAtkins> noamr: Reason I wanted to call it @navigation, two reasons but not integral
<TabAtkins> noamr: First it's a qualified navigation, not a qualified VT. Sounds wierd to say "same origin view transition"
<TabAtkins> noamr: Also sounds a bit funky to have "view transtion between these url patterns"
<TabAtkins> noamr: Also we envision this being general navigation customization later. If you want to hold the page for a little bit while loading the new one, that's a generic feautre, not VT-specific.
<TabAtkins> noamr: Also if we want to disallow UA transitions, this is a good way to do it.
<TabAtkins> noamr: Like swipe UI
<TabAtkins> noamr: So that's why we think a generic name is better
<astearns> ack khush
<TabAtkins> noamr: But we're also okay with saying "don't try to solve those future cases yet"
<fantasai> I think disabling UA transitions fits fine into an @view-transitions or @page-transitions rule
<TabAtkins> khush: Right now you say "same-origin"
<TabAtkins> khush: If you later have urls, "same-origin" is the same as a very general URL
<noamr> I kind of like @page-transitions
<noamr> q+
<TabAtkins> khush: I think I convinced mysefl against this, never mind
<fantasai> I kind of do too, except now I'm wondering if that might conflict with paged media page turn transitions :)
<fantasai> if we ever go there
<TabAtkins> khush: Also, the old document can be held, until you have a response header that says the navigation will be successful
<fantasai> could do @nav-transition
<TabAtkins> khush: that's the extent of info we have for now that we can provide to the old document
<fantasai> (we already abbreviation navigation to nav in the nav-properties)
<zcorpan> I don't like @page-transition because it sounds like it's related to @page
<astearns> ack noamr
<TabAtkins> agree, zcorpan
<TabAtkins> noamr: Some name bikesheds in IRC
<TabAtkins> noamr: Suggestion was "@page-transition", we have a "pageTransition" event in JS that is exactly this sort of thing.
<TabAtkins> noamr: But elika mentioned something about wanting to do a paged-media transition at some point, I'm not sure I udnerstand that.
<TabAtkins> zcorpan: Yeah but the existing @page is what clashes
<fantasai> we already have named pages in pagd media, so actually defining classes of transitions would be pretty straightforward...
<TabAtkins> astearns: REason to not use @view-transition?
<TabAtkins> noamr: Just think this is qualifying the navigation, not the view-transition.
<TabAtkins> zcorpan: You can do a view-transition without a nav, but this only does navigation VTs. So just "@view-transition" seems incorrect
<astearns> that makes sense
<TabAtkins> miriam: Is there a chance in the future that all VTs could be controlled here?
<TabAtkins> noamr: For @auto-view-transition, I think it could maybe be trigger by the Navigation API automatially
<zcorpan> @auto-view-transition-on-navigation
<TabAtkins> noamr: One thing is we can call it @view-transition or @auto-view-transition, and then call the descriptor `trigger`, with values "navigation" or "none"
<TabAtkins> astearns: I think we have objections to @navigation, and anything with @page-*
<TabAtkins> astearns: We have @view-transitions or @auto-view-transitions
<TabAtkins> astearns: Other options?
<TabAtkins> khush: Why the "auto"?
<bramus> q+
<astearns> ack bramus
<TabAtkins> noamr: To make it clear this doesn't control VTs in general, specifically only those that are auto-created by the UA.
<TabAtkins> bramus: At the previous f2f I floated @config, it's super generic and could maybe apply here.
<zcorpan> @view-transition { trigger: navigation; ... } seems ok
<khush> +1
<TabAtkins> TabAtkins: One of the objections to @navigation was it was too generic, so going even more generic seems unlikely to work
<zcorpan> @view-transition same-origin { trigger: navigation; ... }
<noamr> @view-transition { trigger: navigation }
<noamr> @view-transition same-origin { trigger: navigation }
<fantasai> if it's not triggered by navigation, does same-origin still make sense?
<TabAtkins> noamr: Another thing we put to the side is we want this rule to be nestable in MQ
<khush> the other keyword trigger takes is "none".
<fantasai> TabAtkins: The moment a navigation happens is when you figure out when it happens
<fantasai> TabAtkins: having it be conditional on MQ makes sense
<TabAtkins> astearns: I think that's neough bikeshedding for today. Suggest we resovle on Noam's proposal in IRC, we can bikeshed later.
<TabAtkins> astearns: Any objection to `@view-transition same-origin { trigger: navigation | none; }`
<TabAtkins> RESOLVED: Accept the final syntax proposal.
<TabAtkins> fantasai: Wondering if the prelude and trigger should swap places. Unsure what `trigger: none` would do.
<TabAtkins> astearns: In interest of time, I suggest opening an issue for that.
<zcorpan> none would do nothing
fantasai commented 11 months ago

I'm not sure that

@view-transition same-origin { trigger: <any-value-other-than-navigation> }

makes any sense. Should it maybe be

@view-transition navigation {
   origin: same-origin;
}

or something else?

noamr commented 11 months ago

I'm not sure that

@view-transition same-origin { trigger: <any-value-other-than-navigation> }

makes any sense. Should it maybe be

@view-transition navigation {
   origin: same-origin;
}

This doesn't work because it doesn't let you customize classes etc based on URL. The URLs/types need to be in the matcher rather than in the descriptor.

or something else?

Other suggestions?

noamr commented 11 months ago

Perhaps

@view-transition navigation(same-origin) {
  behavior: trigger;
}

Later it can be extended like

@view-transition navigation back from same-origin to urlpattern("...") {
  behavior: trigger;
}
noamr commented 11 months ago

Some more bikeshedding options:

@nav-transition same-origin { behavior: trigger };

@view-transition same-origin-navigation { behavior: trigger }

@navigation-behavior same-origin { view-transition: trigger; }
bokand commented 11 months ago

I'm not sure that

@view-transition same-origin { trigger: <any-value-other-than-navigation> }

makes any sense.

Wouldn't this just be an explicit opt-out (which is the default).

If an opt-out that's the default seems redundant, could we just omit trigger entirely? (i.e. the existence of the at-rule implies opt-in). Examples:

@view-transition same-origin-navigation;

@view-transition same-origin-navigation and history-back {
  typeNames: slide-in reverse;
} 
noamr commented 11 months ago
@view-transition same-origin-navigation;

@view-transition same-origin-navigation and history-back {
  typeNames: slide-in reverse;
} 

It came out in the TAG review that a standalone rule like @view-transition same-origin-navigation; feels a bit inconsistent with the rest of CSS. It's arguable but I can see that point.

khushalsagar commented 10 months ago

@noamr how does this syntax deal with https://github.com/w3c/csswg-drafts/issues/8784? We want transitions to not occur for reloads by default but let authors configure it. Since this can be done in script using the navigate event, seems ok if we punt on a declarative hook for it. But I wasn't sure what the plan for that is with this syntax.

noamr commented 10 months ago

@noamr how does this syntax deal with #8784? We want transitions to not occur for reloads by default but let authors configure it. Since this can be done in script using the navigate event, seems ok if we punt on a declarative hook for it. But I wasn't sure what the plan for that is with this syntax.

In short, @view-transition reload { trigger: navigation} (replace with whatever name we end up with for the rule etc).

The nice thing about reload is that it replaces both the URLs AND the navigation type, so we don't have to bother with composing reloads with other qualifier. A VT-navigation rule is either reload without anything else, or whatever else (same-origin, particular URLs with from/to, back, etc) - mutually exclusive.

khushalsagar commented 10 months ago

I'm trying to understand what our base qualifiers are. IIUC, the idea is that going forward these base qualifiers can be combined with each other (using and/or operators). I was expecting those to be:

same-origin is simply a shorthand for to: urlpattern(/*) (any same-origin URL).

But sounds like you're suggesting reload being another base qualifier which can't be combined with any other qualifier. Is that reasonable? For example, what happens if there is a reload which results in a same-site navigation after redirects. Don't we want authors to be able to express that with something like @view-transition same-site reload { trigger: navigation; }.

noamr commented 10 months ago

You're right that redirects might make it so that a reload doesn't necessarily mean the same URL/origin, so perhaps it needs to be @view-transition same-origin reload.

About the qualifiers, I'd prefer to look at them more from a user intent standpoint rather than from technical history/navigation terms like push/replace.

"reload" and "back" are clear user experience intents, also "forward", "jump to some place in history", or "jump to a random URL in this origin" (address bar, bookmark, extension etc), and of course a normal navigation like links/forms.

The way I see it, the opt-in rule applies to some of these intents. By default, probably to navigate+forward+back, and arguably jump. It applies to reload only if explicit. So @view-transition same-origin actually means something like @view-transition (navigate or back or forward) from urlpattern("/*") to urlpattern("/*") and @view-transition same-origin reload means @view-transition (reload) from urlpattern("/*") to urlpattern("/*"). We can perhaps keep the same-origin implicit when reload is present, but I'm not sure we have to decide on this now. Perhaps this discussion can continue in #8784? Not sure it affects the default opt-in that much.

khushalsagar commented 10 months ago

Sorry I'm still not following how we're dealing with the combination of nav type + from/to url. Every combination of these 2 is possible. So if an author has CSS like:

@view-transition same-site {
  trigger: navigation;
}

@view-transition reload {
  trigger: navigation;
}

What happens if there is a reload which results in a same-site navigation? Your comment above sounds like all the qualifiers are a combination of nav type and from/to url. "same-origin" means any same-origin url of type "navigate", "back" and "forward". Presumably "same-site" would cover the same nav types. And "reload" means only same-origin reload navigations?

We can perhaps keep the same-origin implicit when reload is present, but I'm not sure we have to decide on this now.

Asking this right now because IMO "same-origin" should only be about the from/to url. Overloading the nav type into it is not a good idea. So I'd expect @view-transition same-origin { trigger: navigation; } to include reloads.

vmpstr commented 10 months ago

My interpretation of what @noamr is saying is that we can treat (navigation, back, forward) as the implicit default navigation type.

I agree with @khushalsagar that my understand of same-origin is to be specifically about from/to, and not the type of getting from from to to.

The syntax that I like is something like

@view-transition <<route>> <<navtype>> { ... }

Where

<<route>> = '' | (from: <urlpattern> || to: <urlpattern>) | same-origin | same-site
<<navtype>> = '' | (navigation || back || forward || reload) | including-reload

with an explicit note that explains that if route is '', ie empty, then it is the same as same-origin; if navtype is empty, then it is the same as navigation back forward, but not reload. I've also added including-reload to mean the default ones, and reload, meaning everything.

So with this syntax, I think we can express everything? Specifically, @view-transition same-origin means it doesn't include reloads, and it's about going from /* to /*.

To answer @khushalsagar's question, in this syntax @view-transition reload means "same origin reload only". If you want to capture all same-site navigations including reloads, then that's @view-transition same-site including-reload.

noamr commented 10 months ago

Sorry I'm still not following how we're dealing with the combination of nav type + from/to url. Every combination of these 2 is possible. So if an author has CSS like:

@view-transition same-site {
  trigger: navigation;
}

@view-transition reload {
  trigger: navigation;
}

What happens if there is a reload which results in a same-site navigation? Your comment above sounds like all the qualifiers are a combination of nav type and from/to url. "same-origin" means any same-origin url of type "navigate", "back" and "forward". Presumably "same-site" would cover the same nav types. And "reload" means only same-origin reload navigations?

I think so. Mainly because a reload with cross-origin redirects is something that feels unexpected and uncommon. Edge case?

We can perhaps keep the same-origin implicit when reload is present, but I'm not sure we have to decide on this now.

Yes exactly

Asking this right now because IMO "same-origin" should only be about the from/to url. Overloading the nav type into it is not a good idea. So I'd expect @view-transition same-origin { trigger: navigation; } to include reloads.

I see the value in having a clean separation between URLs and types, and having same-origin mean only the URLs.

But I think there is greater value in reasonable defaults. Putting UX first, view transitions on reload is something unexpected and needs to be handled a bit like an edge case, and in most cases not have a transition there at all unless explicitly requested. This was the tone of this CSSWG resolution.

The same argument for reasonable defaults (which I think is consistent with a lot of CSS) goes for having reloads be same-origin only by default.

As for being conceptually clean, I'd say that in this case same-origin does mean just the from/to URLs, and since there is no type defined, we go with the specified "default set of navigation types" - which are navigate/back/forward/(maybe also jump? not sure).

khushalsagar commented 10 months ago

The same argument for reasonable defaults (which I think is consistent with a lot of CSS) goes for having reloads be same-origin only by default.

My concern wasn't with the default, but whether the non-default case is possible : reload with a same-site navigation. In general, I'd say our syntax should ensure that any combination of mutually exclusive navigation params (same vs cross doc, from/to url and nav type) can be expressed. We should have a good reason to disallow a combination and it being an edge case is not a good one.

The syntax @vmpstr proposed above sounds good in that regard. One thing I'd say is to include <<doc-change>> to the qualifier as well.

@view-transition <<route>> <<navtype>> <<doc-change>> { ... }

where

<<doc-change>> = "same-document | cross-document"

A few more clarifications around it:

@noamr does that sound reasonable to you?

If the above sounds good then a couple of questions come to mind:

noamr commented 10 months ago

The same argument for reasonable defaults (which I think is consistent with a lot of CSS) goes for having reloads be same-origin only by default.

My concern wasn't with the default, but whether the non-default case is possible : reload with a same-site navigation. In general, I'd say our syntax should ensure that any combination of mutually exclusive navigation params (same vs cross doc, from/to url and nav type) can be expressed. We should have a good reason to disallow a combination and it being an edge case is not a good one.

The syntax @vmpstr proposed above sounds good in that regard. One thing I'd say is to include <<doc-change>> to the qualifier as well.

@view-transition <<route>> <<navtype>> <<doc-change>> { ... }

where

<<doc-change>> = "same-document | cross-document"

I wouldn't do the same-doc thing in CSS at all, rather have this in JS - something like navigation.enableSameDocumentAutoViewTransitions = true which would make this whole thing somehow work magically with the navigation API

A few more clarifications around it:

  • Each at-rule declaration must provide a route, nav type and doc-change. If not supplied, there will be a default.
  • The relationship between each qualifier is "and", i.e., the at-rule reads as "navigation to url(a) and back".
  • The default for route is same-origin, nav type is all navigations excluding reload and doc-change is cross-document.

@noamr does that sound reasonable to you?

If the above sounds good then a couple of questions come to mind:

  • I'm assuming we'll allow an "or" type syntax for each qualifier for use-cases like from: urlpattern(a),urlpattern(b). But the relationship between qualifiers is and. So if you want the rule to say "back or navigation to urlpattern(a)", that needs 2 at-rule declarations. That sounds fine to me, just wanted to confirm.

Not sure yet, I don't think we're there but sounds OK for now.

  • Why do we need to require the "same-origin" qualifier? Sounds like similar to nav type, the default value of same-origin avoids the need for it.

It's not strictly necessary. I think it was your suggestion to make it explicit when reading that this only applies to same origin navigation. I'm ok with also making it an implicit default. It wouldn't be the first thing in the web platform that's implicitly same-origin by default.

khushalsagar commented 10 months ago

I wouldn't do the same-doc thing in CSS at all, rather have this in JS - something like navigation.enableSameDocumentAutoViewTransitions = true which would make this whole thing somehow work magically with the navigation API

Ok. I'm fine with punting on this.

Not sure yet, I don't think we're there but sounds OK for now.

Aren't we resolving on a syntax which requires an "and" relationship between the qualifiers? I figured that's why we should make sure this is fine right now.

It's not strictly necessary. I think it was your suggestion to make it explicit when reading that this only applies to same origin navigation. I'm ok with also making it an implicit default.

I suggested this because it wasn't clear to me how the syntax will be extended to support same-site. Now that its more clearly laid out, it makes sense to be able to omit it.

noamr commented 10 months ago

I wouldn't do the same-doc thing in CSS at all, rather have this in JS - something like navigation.enableSameDocumentAutoViewTransitions = true which would make this whole thing somehow work magically with the navigation API

Ok. I'm fine with punting on this.

Not sure yet, I don't think we're there but sounds OK for now.

Aren't we resolving on a syntax which requires an "and" relationship between the qualifiers? I figured that's why we should make sure this is fine right now.

We're not suggesting the qualifiers yet. But I imagine having and/or/() like media queries.

It's not strictly necessary. I think it was your suggestion to make it explicit when reading that this only applies to same origin navigation. I'm ok with also making it an implicit default.

I suggested this because it wasn't clear to me how the syntax will be extended to support same-site. Now that its more clearly laid out, it makes sense to be able to omit it.

Great. Let's suggest this when we discuss the name.

khushalsagar commented 10 months ago

We're not suggesting the qualifiers yet. But I imagine having and/or/() like media queries.

It's likely fine, I'm just convincing myself that we'll be able to add both and/or operators with the qualifiers later. For example, having no qualifiers implicitly expands to both default values + "and" operator between them. But the author will be able to override the defaults by providing an explicit value for each qualifier + whether its "and"/"or".

@view-transition { ... }

/* The above expands to the following */
@view-transition <<route>> and <<navtype>>  and /* any other potential qualifiers */ { ... }

@view-transition <<route>> or <<navtype>> { ... }

/* The above will expand to the following */
@view-transition <<route>> or <<navtype>>  and /* any other potential qualifiers */ { ... }

Great. Let's suggest this when we discuss the name.

SGTM!

noamr commented 10 months ago

We're not suggesting the qualifiers yet. But I imagine having and/or/() like media queries.

It's likely fine, I'm just convincing myself that we'll be able to add both and/or operators with the qualifiers later. For example, having no qualifiers implicitly expands to both default values + "and" operator between them. But the author will be able to override the defaults by providing an explicit value for each qualifier + whether its "and"/"or".


@view-transition { ... }

/* The above expands to the following */
@view-transition <<route>> and <<navtype>>  and /* any other potential qualifiers */ { ... }

What are the other potential qualifiers?

@view-transition <<route>> or <<navtype>> { ... }

I think this would expand to (<<route>> and <<default-nav-types>>) or (<<navtype>> and same-origin)

khushalsagar commented 10 months ago

What are the other potential qualifiers?

Same vs cross-doc was the only other one I had, but I can see that being specified in JS instead of CSS. Can't think of anything else but it's good to ensure its possible to add more going forward.

I think this would expand to (<<route>> and <<default-nav-types>>) or (<<navtype>> and same-origin)

Hmmm, that took me by surprise. Reading the author declaration, that's not what I would've expected. FWIW, @vmpstr pointed out that this use-case can be achieved with 2 blocks like:

@view-tranition <<route>> and all-nav-types { ... }
@view-tranition all-routes and <<navtype>> { ... }

So whichever expansion we take, we won't be limiting authors. We can decide based on what authors would intuitively expect.

nickcoury commented 10 months ago

One minor comment on

<<navtype>> = '' | (navigation || back || forward || reload) | including-reload

It could be useful to provide an identifier for a multi-entry jump e.g. back(1), navigation(-3), back(*) or something like that. Many well-formed transitions+animations rely on a guarantee on which page(s) can be directly connected.

Jumping between two arbitrary pages that are many navigations apart might generate unexpected motion with VT API annotations, and it would be great to have a way to explicitly disable this or specify a simpler animation like a full-page cross-fade.

This could apply to the opt-in here, and would also be useful for the actual CSS styling specified. Using cascading rules to override will give power to customize e.g.

@view-transition same-site (back(*), forward(*) { trigger: navigation }

::view-transition-old(root) back(*),
::view-transition-new(root) back(*) {
  animation: simple-back-animation;
}

::view-transition-old(root) back(1),
::view-transition-new(root) back(1) {
  animation: advanced-back-animation;
}

(not bikeshedding here with the syntax, just the functionality)

noamr commented 10 months ago

One minor comment on

<<navtype>> = '' | (navigation || back || forward || reload) | including-reload

It could be useful to provide an identifier for a multi-entry jump e.g. back(1), navigation(-3), back(*) or something like that. Many well-formed transitions+animations rely on a guarantee on which page(s) can be directly connected.

Jumping between two arbitrary pages that are many navigations apart might generate unexpected motion with VT API annotations, and it would be great to have a way to explicitly disable this or specify a simpler animation like a full-page cross-fade.

This could apply to the opt-in here, and would also be useful for the actual CSS styling specified. Using cascading rules to override will give power to customize e.g.

@view-transition same-site (back(*), forward(*) { trigger: navigation }

::view-transition-old(root) back(*),
::view-transition-new(root) back(*) {
  animation: simple-back-animation;
}

::view-transition-old(root) back(1),
::view-transition-new(root) back(1) {
  animation: advanced-back-animation;
}

(not bikeshedding here with the syntax, just the functionality)

Suggesting that back is exactly back(1), and jump is everything else (traversing more than +-1 back/forward, or navigating via URL bar etc)

khushalsagar commented 10 months ago

jump is everything else (traversing more than +-1 back/forward, or navigating via URL bar etc)

The idea sounds nice but its unfortunate that navigation type in CSS will diverge from navigation type in JS defined by the navigation API. This might be inevitable if we can't change the JS navigation type in a backwards compatible way but worth trying to keep these consistent to the extent possible. @domenic @natechapin FYI.

Could we organize the CSS navigation types as sub-types of the JS versions?