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] Define navigation descriptor for @view-transition #8783

Closed
khushalsagar opened this issue May 1, 2023 · 17 comments
Closed
Labels
css-view-transitions-2 View Transitions; New feature requests Needs Edits

Comments

@khushalsagar
Copy link
Member

There are a class of navigations which are initiated via the browser UI:

  • Entering a url in the URL bar.
  • Back/forward buttons in the browser UI.

It's unclear whether we should initiate a ViewTransition for these. The worry is that we'd hit navigation paths the current Document doesn't expect. For example, there is no link to the Document the user entered in the URL bar in the contents of the current Document. So the author will need to ensure there is a transition defined between any 2 same-origin URLs. They can always use the cross-fade setup by the UA CSS.

If we don't enable ViewTransitions for navigations initiated using the URL bar, it makes handling back/forward slightly complicated. Using back/forward in the browser UI is a common navigation pattern. If A -> B had a ViewTransition, we likely also want one for B -> A triggered by the back button. So we'll have to carve out the subset of cases where back/forward in the UI use ViewTransitions.

@css-meeting-bot
Copy link
Member

The CSS Working Group just discussed [css-view-transitions-2] Should ViewTransitions be triggered for browser initiated navigations, and agreed to the following:

  • RESOLVED: Leave these cases explicitly undefined in the spec
The full IRC log of that discussion <fantasai> vmpstr: same spirit, but about browser-initiated navigation
<fantasai> vmpstr: it is a navigation, but should that do a transition?
<fantasai> vmpstr: reason it's a question is that the page might not expect that route to be animatable
<fantasai> vmpstr: but at the same time, if it's supported, could do a transition
<fantasai> noamr: regardless of address bar, we do support for bak/forwad in history
<khush> q+
<fantasai> noamr: but that could also create unexpected routes
<fantasai> noamr: address bar is a special case of something general, but many things that we do want to support
<fantasai> noamr: e.g. jump in history
<astearns> ack khush
<fantasai> khush: my take on this is that it's hard to figure out all the cases where we can say this navigation was intentional from the author
<fantasai> khush: easier to say that it's all same-origin
<fantasai> khush: and give some knobs for controlling which navigations trigger
<fantasai> khush: right now you would need some scrijpt
<fantasai> khush: but there are proposals for making that declarative
<fantasai> vmpstr: at least as a user, when I type into the URL bar, I'm beginning a new experience
<fantasai> vmpstr: I don't expect there to be anything to persist my cognitive state
<fantasai> vmpstr: so in that case a transition doesn't help me
<fantasai> vmpstr: so good point about back/forward, can also jump multiple entries
<fantasai> vmpstr: I would argue again that you're breaking your experience
<fantasai> vmpstr: so non-transition animation is good
<bramus> seems reasonable
<fantasai> vmpstr: happy to be convinced otherwise, but don't think we should try to do transition in every ossible place
<fantasai> vmpstr: but rather for cases where devs expect
<fantasai> khush: you mean user
<fantasai> vmpstr: no I mean developer
<fantasai> khush: if the user copies URL form a link and pastes...
<fantasai> vmpstr: I would still argue it's still a new thing
<dbaron> (I think I agree with vmpstr.)
<fantasai> Nicole: When you go from one page to anotehr, and the other origin doesn't expect it either, isn't this also unexpected/
<fantasai> vmpstr: for cross-origin, second page did not set up that navigation transition
<fantasai> s/vmpstr/Nicole/
<astearns> (I think I also agree with vmpstr - no transitions for browser-initiated navigations)
<fantasai> vmpstr: Agree, that's why we didn't pursue cross-origin originally
<fantasai> vmpstr: it's harder problem to work out
<fantasai> nicole: I think it would not be good experience if they have to say exactly which pages they want, could have thousands
<fantasai> nicole: so should be easy to opt in or out of having transitions
<khush> q+
<fantasai> khush: Phrasing is interesting wrt user vs dev expectations
<fantasai> khush: if i have transition from A to B, and I past in the URL
<fantasai> khush: as a developer I would expect the transition
<fantasai> khush: I wouldn't know how the navigation is triggered
<fantasai> khush: as a user, type in the new URL, the transition keeps the visual context
<fantasai> khush: as a user I think the animation would line up with what I epxect to see
<fantasai> khush: but yes, I'm curious about what web developers think
<fantasai> khush: we're not sure if how navigation was triggered changes things
<astearns> ack fantasai
<astearns> ack khush
<vmpstr> fantasai: need more information from authors and users, next steps to collect more expectations?
<fantasai> astearns: Anyone else with an opinion?
<fantasai> astearns: it sounds like just in the room, between khush and vlad we've got 2 different opinions
<fantasai> vmpstr: "browser-initiated navigation" isn't specified, and there are lots of types
<fantasai> vmpstr: I'm not sure this needs to be interoperable because not exactly web-visible
<vmpstr> s/vmpstr/noamr/
<fantasai> s/vmpstr/noamr/
<fantasai> astearns: Seems like we should just keep this issue open and see if we get a better sense of author and user expectations
<fantasai> nicole: I'm curious what % of users modify the URL in the navigation bar
<fantasai> nicole: seems like a nerdy power-user thing to do
<fantasai> nicole: so maybe not something to resolve on
<astearns> I do it, so I assume it’s something very few other people do
<fantasai> hober: I think the simple answer is that enough of them do that it matters.
<fantasai> khush: Out of all the navigation, figure out how many same-origin cross-document navigations happen, if the number is low enough take the easier option
<fantasai> khush: jumping multiple steps in history is also power user
<hober> qq+ myles
<fantasai> myles: They are not rare. Typing into the URL bar is not power user option
<noamr> q+
<hober> q- myles
<fantasai> khush: for a same-origin cross-document navigation... it seems like cross-origin is more common for typing
<astearns> ack khush
<astearns> ack fantasai
<noamr> q-
<vmpstr> fantasai: don't define in the spec, and revisit later
<fantasai> fantasai: I suggest we leave these cases explicitly undefined in the spec
<fantasai> faceless: and revisit later if we end up with a definite opinion
<fantasai> astearns: so proposed resolution is to leave undefined
<fantasai> RESOLVED: Leave these cases explicitly undefined in the spec

@khushalsagar
Copy link
Member Author

The resolution was to leave this undefined but we should add a non-normative note mentioning this.

@noamr
Copy link
Collaborator

noamr commented Oct 26, 2023

I think this is a good time to revisit this (as mentioned in the minutes by @fantasai, "we should revisit this later").
Since we're defining the initial navigation types as auto and none, we should be explicit about what auto means.
Leaving this unspecified would leave an open interop question for this type of navigation.

I propose that auto would mean normal | back | forward, where normal means a normal click link, form submit etc), and back / forward mean a history traversal of -1 or +1 exactly.

We can then have reload and jump as optional navigation descriptor values that are not included in auto but can be explicitly enabled.

To be explicit, the proposal is:

  • back means navigationType == "traverse" && delta == -1
  • forward means navigationType == "traverse" && delta == 1
  • normal means (navigationType == "push" || navigationType == "replace") && userInvolvement !== "browser UI"
  • auto means back | forward | normal
  • Anything else (reload, jump-traversals, browser UI navs) is yet to be defined, but not included in auto.

@khushalsagar
Copy link
Member Author

Any reason to disallow transitions for script initiated traversals with delta > 1. It seems like by definition the author expects that route.

I think we can have auto include all navigations where user navigation involvement is not browser UI. For the browser UI case, only include traverse with a delta of 1. Since any other browser UI initiated navigation might be an unexpected route for the author.

@domenic @natechapin for an opinion too.

@domenic
Copy link
Collaborator

domenic commented Nov 17, 2023

I was asked to comment here but don't quite understand the design goals. Some general principles and observations that might help:

  • I think there are some implicit filters here that are not stated. Something like, cross-document, and same-origin? Can someone confirm?

  • In terms of what authors expect, I think there's really only two meaningful tiers: link clicks/author-initiated JS navigations, and literally-everything. Saying that authors expect back button presses but don't expect manual same-origin URL hacking seems wrong to me. (In part, because once you've done the URL hacking to generate an arbitrary X -> Y push navigation, you can click the back button to generate an arbitrary Y -> X traverse navigation.)

  • In the navigation API, we expose to authors the ability to be notified of almost all navigations, except for browser-UI non-traverse. The reasoning there was not really about what authors expect, but instead about whether we could meaningfully allow cancelation or interception. For browser-UI non-traverse we do not offer cancelation or interception, because that wasn't possible before the navigation API existed and we didn't want to introduce a new capability.

    Even if the reasoning isn't the same, aligning on that same boundary might make things easier to understand for authors.

  • In terms of what we see authors filtering out, we see lots of usage of these NavigateEvent properties: hashChange, formData, and downloadRequest. Authors mostly don't want to intercept those kinds of navigations. (Although intercepting formData is relatively popular.)

  • It seems like you're trying to do two things: summarize the full power of the navigation API into a set of easy keywords for common use cases, and figure out the default auto behavior.

    For the former, I'd be cautious and minimal. Since you're not going to be able to give developers the full power of e.destination.url.endsWith("/foo") && !e.hashChange && e.userInitiated && e.info === "bar" in CSS, the default assumption should be that developers use JS to connect up their CSS appropriately. So it's only for truly-simple cases, where you have web developers explicitly saying "I really want to filter out the X transitions with no special cases", that you want to create new CSS keywords. back, forward, and reload are good guesses, but it'd be best if you could point to explicit developer demand, ideally in the form of building a realistic demo. In particular, to show that "I really want to filter out the back transitions" doesn't end up being "I really want to filter out the back transitions, except when going back to the homepage" or something like that.

    For the latter, whichever route you go, I really appreciate the efforts to phrase it in terms of the navigation API. Keep that up :)

@noamr
Copy link
Collaborator

noamr commented Nov 17, 2023

I was asked to comment here but don't quite understand the design goals. Some general principles and observations that might help:

  • I think there are some implicit filters here that are not stated. Something like, cross-document, and same-origin? Can someone confirm?

Confirmed. This is in the current spec.

  • In terms of what authors expect, I think there's really only two meaningful tiers: link clicks/author-initiated JS navigations, and literally-everything. ... (In part, because once you've done the URL hacking to generate an arbitrary X -> Y push navigation, you can click the back button to generate an arbitrary Y -> X traverse navigation.)

That's a good point.

@noamr noamr removed the Needs Edits label Nov 17, 2023
@khushalsagar
Copy link
Member Author

khushalsagar commented Nov 17, 2023

Thanks for the feedback @domenic. Putting a CSS snippet for the resolved syntax for context on the replies below. This would be valid CSS for both the old and new Documents.

/* This rule is used to decide whether a View Transition will be done for a navigation */
@view-transition {
   /* This is a transition opt-in for all navigations classified as "auto" */
   navigation: auto;
   
   /* This is a developer provided custom ident to conditionally apply CSS specific to a transition */
   type: home-to-back;
}

@media (prefers-reduced-motion) {
    @view-transition {
       /* This is a transition opt-out for all navigations */
       navigation: none;
    }
}

/* Example of how type is used to activate CSS specific to a transition */
html:active-view-transition(home-to-back) #target {
   view-transition-name: target;
}

I think there are some implicit filters here that are not stated. Something like, cross-document, and same-origin? Can someone confirm?

Just to clarify why this isn't obvious. We broke down the parameters to identify a navigation as-follows:

  • Source or destination URL
    This implicitly identifies whether the navigation is same-origin. Currently the CSS opt-in applies to all same-origin URLs. Authors will have to use script if they need to enable transitions to specific URLs. We'll eventually add from/to descriptors to the at-rule to make it declarative.

  • Same vs cross document
    Currently the CSS opt-in only applies to cross-document navigations. Authors can trigger a transition via document.startViewTransition() for same-document navigations. We've discussed a declarative opt-in for same-document navigations but how is TBD. Should be a new descriptor if it needs to be in the at-rule.

  • Everything else
    This is what the navigation descriptor is supposed to cover.

The goal of this issue it to define the values for the navigation descriptor and which navigation each one matches with. Based on your feedback, I think the following keywords makes sense:

  • all: This matches all navigations that are observable with the navigation API and is an opt-in. Authors would use this if they are setting up the opt-in via script events (like navigate) on the old Document and activationInfo on the new Document.

  • none: This matches all navigations that are observable with the navigation API and is an opt-out.

  • auto: This matches all navigations the author is guaranteed to expect: link clicks/author-initiated (IIUC the spec way to say this would be user navigation involvement != "browser UI") except reload. We're excluding reload based on developer feedback (see [css-view-transitions-2] Should ViewTransitions be triggered for reloads? #8784).

So it's only for truly-simple cases ... that you want to create new CSS keywords

Agreed. Btw, since the CSS at-rule is both an opt-in and a setter for type, the latter is another motivation for new CSS keywords. For example, it would be common to customize a directional animation based on whether its a back or fwd navigation. But I agree that we should add it once there's been enough use of the JS API and we see what the common patterns are.

@khushalsagar khushalsagar changed the title [css-view-transitions-2] Should ViewTransitions be triggered for browser initiated navigations [css-view-transitions-2] Define navigation descriptor for @view-transition Nov 17, 2023
@bokand
Copy link
Contributor

bokand commented Nov 20, 2023

This matches all navigations the author is guaranteed to expect: link clicks/author-initiated (IIUC the spec way to say this would be user navigation involvement != "browser UI") except reload.

Does this intentionally drop history traversal? My understanding is that user navigation involvement for history is "browser UI" if performed by the user from the UI and "none" for script initiated traversals.

@khushalsagar
Copy link
Member Author

Does this intentionally drop history traversal?

It drops history traversal via browser UI but not if it was initiated by script based on this comment above:

Saying that authors expect back button presses but don't expect manual same-origin URL hacking seems wrong to me. (In part, because once you've done the URL hacking to generate an arbitrary X -> Y push navigation, you can click the back button to generate an arbitrary Y -> X traverse navigation.)

Although now that you asked, we could have auto include back/fwd navigations from the browser UI if the push navigation was done by script?

@noamr
Copy link
Collaborator

noamr commented Nov 21, 2023

  • all: This matches all navigations that are observable with the navigation API and is an opt-in. Authors would use this if they are setting up the opt-in via script events (like navigate) on the old Document and activationInfo on the new Document.
  • none: This matches all navigations that are observable with the navigation API and is an opt-out.
  • auto: This matches all navigations the author is guaranteed to expect: link clicks/author-initiated (IIUC the spec way to say this would be user navigation involvement != "browser UI") except reload.
    We're excluding reload based on developer feedback (see [css-view-transitions-2] Should ViewTransitions be triggered for reloads? #8784).

Based on @domenic's feedback, which I resonate with, I think that for now auto should mean "everything except reload", and for the time being not try to be more opinionated than that about "browser UI". People can create more precise distinction if they wish using JS. If we get feedback later that some of those browser-UI transitions are unexpected and people do the same thing consistently in JS, we can add new keywords.

@khushalsagar
Copy link
Member Author

My suggestion was based on the idea that all is the keyword used when the actual decision is made in script. That's why it encompasses all navigations observable in script. And auto is the keyword used when the author wants the browser to enable the transition only if a route is "expected". So they don't need to add script to make that decision.

I see your point though, we haven't had enough developer feedback to be opinionated about what a generic keyword like auto should mean. The only feedback on unexpected transitions is around reload. So maybe we go with what you said and choose a better name than "auto" like "all-except-reload"?

The above implies that to begin with authors won't be able to trigger a transition on reload at all. We'll add that if there's demand for it.

@noamr noamr added the Agenda+ label Jan 2, 2024
@noamr
Copy link
Collaborator

noamr commented Jan 3, 2024

Proposal from internal sync:

  • Use the name auto as per existing spec.
  • The name auto should not match reloads, and also not match browser-UI non-traverse navigations (e.g. typing in the URL bar). This matches the behavior of the navigation API, where this type of navigation is not interceptable.
  • The rationale for this is not about an unexpected route, but rather that:
    a. typing in the URL address bar and switching URLs. might "feel like" a new navigation rather than a transition between pages, so for now starting conservatively without those navigations feels safe.
    b. Because these navigations are not cancelable/interceptable, there's no way to customize/skip the transition in the JS, which is still an important piece of cross-document view transitions.

In summary, autowould match:

  • Any traverse navigation
  • Any push or replace navigation whose user involvement is not browser UI.

@noamr
Copy link
Collaborator

noamr commented Jan 9, 2024

One thing that we'd want to resolve in with the WG is whether programmatic reloads (e.g. location.reload()) should be included in auto. As per the current spec they don't, but they're interceptable via the navigation API.

If we enable it, skipping the transition for a reload in the outgoing page is still possible, and would look like this:

navigation.addEventListener("navigate", async e => {
  if (e.navigationType === "reload") {
     const sheet = new CSSStyleSheet();
     sheet.replaceSync("@view-transition { navigation: none }");
     // Note that there's no need to restore it because a `reload` cancels BFCache. 
     // If this was not a `reload` we'd have to remove the sheet from the adopted stylesheets on `pagehide`.
     document.adoptedStyleSheets.push(sheet);  
  }
});

@bokand
Copy link
Contributor

bokand commented Jan 9, 2024

Is there a reason why programmatic reloads should be treated specially? In particular, it seems a bit weird that if we later added a reload value for the descriptor it would only control browser-ui initiated reloads.

@noamr
Copy link
Collaborator

noamr commented Jan 9, 2024

Is there a reason why programmatic reloads should be treated specially? In particular, it seems a bit weird that if we later added a reload value for the descriptor it would only control browser-ui initiated reloads.

Mainly so that people who use location.reload() for something today and want to enable view-transitions would be able to do it. I'd say that the main reasoning against allowing view-transitions on reloads is for user-initiated reloads in the browser UI. The other reason would be to be consistent with existing web-platform features (namely the navigation API).

@fantasai
Copy link
Collaborator

I think you don't want to include reloads by default, whether user-initiated or script-initiated. If you want to allow them, then add an option for it.

@css-meeting-bot
Copy link
Member

css-meeting-bot commented Jan 10, 2024

The CSS Working Group just discussed [css-view-transitions-2] Define navigation descriptor for @view-transition, and agreed to the following:

  • RESOLVED: auto means push or replace that's not browser ui, or traverse (with any user involvement type), and excludes any reloads
The full IRC log of that discussion <flackr> noamr: we resolved on having a view transition rule with a navigation descriptor having values of auto and none for cross document VTs
<flackr> noamr: we said in the future we'd resolve on what auto means and whether it's the right name
<flackr> noamr: let's figure this out
<flackr> noamr: we think any navigation except reload should be considered auto and automatically trigger a VT
<flackr> noamr: we want to be a bit more aligned with the navigation API. Navigations that are not cancelable should not trigger an auto VT
<flackr> noamr: this mainly includes browser UI navigations, e.g. typing a URL in URL bar
<flackr> noamr: the idea is to align more with this, and say auto means any navigation that is not browser initiated and any navigation that is a traverse navigation (e.g. back/forward)
<flackr> noamr: an outlier to both is reloads, we resolved before they shouldn't be automatically a VT, but reloading via JS can be canceled with the navigation API
<flackr> noamr: the proposal is to call this auto, to include any traverse navigation, any push/replace navigation that is not browser UI initiated, and to discuss whether programmatic reloads should be included, probably not
<Rossen_> ack fantasai
<noamr> q+
<flackr> fantasai: I think saying you can cancel it via JS is not the right way to do this. We want this to work for people not writing JS. By default we can allow for reloads (programmatic or user initiated), but it should be an option
<khush> q+
<flackr> fantasai: we don't know if the author wants to have something reload more invisibly rather than trigger a transition
<flackr> fantasai: e.g. navigating from one catalog to another might look like a page swipe but reload shouldn't. auto shouldn't include these cases and the author should request it explicitly
<Rossen_> ack noamr
<fantasai> s/catalog/catalog page/
<flackr> noamr: programmatic reloads are JS to begin with. We don't know what people use them for. You probably wanted a reload pattern in your application or because you reach a certain state want to force a reload
<flackr> noamr: the idea of hanging off of what can be cancelled via JS kind of made sense for navigations initiated from JS
<flackr> fantasai: the person writing the JS might not be the same person writing the CSS
<flackr> fantasai: the person designing the transitions needs to be able to design this independently
<flackr> noamr: do people have views about excluding browser UI initiated navigations?
<flackr> fantasai: this seems vague, there's a lot. Does this include back/forward?
<flackr> noamr: no, anything except traverse
<flackr> noamr: e.g. bookmarks, typing in url bar, extensions etc
<flackr> fantasai: what is traverse? for clarity
<flackr> noamr: traverse is going back/forward in history or clicking something through the history list
<flackr> Rossen_: what about meta tag refresh?
<flackr> noamr: that would be a reload, or a replace if it goes to a different url
<flackr> noamr: so that's equivalent to a programmatic replace so it wouldn't be considered browser ui
<flackr> noamr: it would have a VT
<flackr> Rossen_: so on every refresh in fantasai's example you'd be flipping pages
<flackr> noamr: yes, because it's like a regular replace navigation
<flackr> fantasai: so to summarize, you want to introduce a keyword that says every navigation initiated by the user or the page except a reload of the page, or a browser UI navigation that is not a ....
<fantasai> s/a ..../history traversal/
<Rossen_> q?
<flackr> noamr: the keyword means any navigation that is not browser ui plus any browser ui traverse (i.e. including links, back/forward, forms, meta redirect)
<flackr> khush: this keyword called user involvement, is an existing thing in the spec we're leaning on. script, activation behavior and browser ui
<flackr> khush: script is like using history api or navigation api
<flackr> khush: activation behavior is where <a> activation triggers navigation
<flackr> khush: browser ui is interaction with browser UX to trigger navigation
<flackr> khush: the desire here to align with the nav API is that it's a bit weird to trigger a VT from a navigation you can't observe via script
<flackr> khush: in that we haven't exposed it to script normally
<flackr> khush: also you can't customize it via JS, so there will be problems with not being able to customize it
<flackr> khush: so i have concerns with only being able to customize it via css
<flackr> khush: html has 4 keywords, push, replace, ?? and traverse
<flackr> s/??/reload
<flackr> khush: if navigation type is push or replace, and user involvement is not browser UI
<Rossen_> q?
<Rossen_> ack khush
<flackr> khush: one class of navigations is your type is push/replace and involvement is not brower UI, i.e. script or activation behavior, this is included
<flackr> khush: for traverse, the html spec has a special carveout because authors often want to include these. For this it should be allowed even if browser ui was involved
<flackr> khush: the fact that you can observe it helps customize
<flackr> Rossen_: does this satisfy concerns / questions?
<flackr> fantasai: yes, and last category is reload.
<flackr> fantasai: ???
<fantasai> s/???/I think we should exclude reload in all modes/
<khush> In summary, auto would match: Any traverse navigation. Any push or replace navigation whose user involvement is not browser UI.
<flackr> noamr: resolution would be auto means push or replace that's not browser ui, or traverse with any user involvement excluding any reloads
<fantasai> s/excluding/, excluding/
<flackr> RESOLVED: auto means push or replace that's not browser ui, or traverse with any user involvement, excluding any reloads
<Rossen_> Zakim, end meeting

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 Needs Edits
Projects
None yet
Development

No branches or pull requests

6 participants