Re: [csswg-drafts] [css-view-transitions-2] Syntax for customizing transitions based on their type (#8960)

_(This reply quickly turned out to be much longer than I expected it to be. It touches a lot of things at once, as they are all interconnected. Please take your time to read it thoroughly as I think it has potential to form an answer to some of the open VT2 questions.)_

I’m also no longer convinced that a single ident that names the transition would cut it. This would require authors to name each and every possible transition between two pages, in each possible direction. That would be a lot of work and a lot of idents.

I see 3 parameters that determine how a page-like transition should animate:

- The _from_ page
- The _to_ page
- The _direction_

Combining these 3, you gain a lot of flexibility:

- Going _from_ `video-overview` _to_ `video-detail` = Visually slide everything towards the ← side
- Going _from_ `video-detail` _to_ `video-overview` = Visually sllde everything towards the → side

The reason for this third _direction_, is to cater for transitions between to pages of the same type. Think of a paginated list where you are at page 5. Going to page 4 or to 6 is going to the same type page, but in a different _direction_.

- Going _from_ `video-archive` page 5 _to_ `video-archive` page 6 = A `forward` _direction_  = Visually slide everything towards the ← side
- Going _from_ `video-archive` page 5 _to_ `video-archive` page 4 = A `backward` _direction_  = Visually slide everything towards the → side

Note: when moving between two pages of a different type, you don’t really need the direction as you can achieve the reversed direction by flipping _from_ and _to_

---

Instead of setting these three parameters as a bag of parameters – where an author can choose how to name them - I think we should make it structured and give them proper names. The reason for this, is to play nice with the almighty browser back button.

Say you have this:

```js
document.startViewTransition({
  updateCallback: () => {
    updateTheDOM();
    updateTheURL();
  },
  to: `video-detail`,
  from: `video-overview`,
});
```

When the user presses the browser’s back button, it’s now easy very to achieve the opposite transition. Because these arguments are named, the UA can automatically swap the `to` and `from` arguments their values.

That way, pressing the browser’s back button after the snippet from just above, is essentially the same as invoking this:

```js
// Note: this is the code that would get run when pressing the browser’s back button. The UA automatically re-runs the original View Transition with the to and from arguments swapped.
document.startViewTransition({
  updateCallback: () => {
    updateTheDOM();
    updateTheURL();
  },
  to: `video-overview`, // 👈 Swapped value!
  from: `video-detail`, // 👈 Swapped value!
});
```

For transitions where `to` and `from` were the same, it’s a matter of flipping `forward` to `backward` and vice versa when pressing back. Again, it would be the UA that takes care of this when pressing the browser’s back button after having done such a transition.

```js
document.startViewTransition({
  updateCallback: () => {
    updateTheDOM();
    updateTheURL();
  },
  to: `video-archive`,
  from: `video-archive`,
  direction: 'backward', // 👈 When going from page 5 to page 4, you are going back in the pagination.
});
```

If you press the browser’s back button after the snippet above, `backward` would become `forward`.

Upon pressing the browser’s reload button, the direction would be overridden as `reload`. That way, authors can also take that into account to set up their animations.

---

So, what about cross-document Navigation you might wonder? Reusing the `@routes` that was already suggested here it would be a matter of naming the routes.

```css
@routes {
  video-overview: urlpattern('/videos');
  video-detail: urlpattern('/videos/watch/:slug');
  video-archive: urlpattern('/videos/archive(/:page_id)?');
}
```

Nothing else is needed besides this block (🎉). These route names would then automatically be used as the `from` and `to` arguments when doing a cross-document navigation. The `from` value is derived from the current page URL, and the `to` value from the URL that you end up at. When pressing the browser’s back button, the argument values get swapped.

<details>
<summary>Sidetracking here: this does not add a way to set the direction to be used.</summary>

This should be possible with a little bit of JavaScript but ideally it should also be possible from within CSS. I am thinking of a way to configure this direction in the `@view-transitions` at-rule _([the one that configures VTs](https://github.com/w3c/csswg-drafts/issues/8048#issuecomment-1640574446))_.

This would require some sort of pseudo that indicates “hey, this was the element that initiated the cross-document navigation” to hook onto. I’m using `:last-active` here, but the name is definitely up for bikeshedding:

```css
.pagination a.next:last-active {
  @view-transitions {
    direction: forward;
  }
}

.pagination a.previous:last-active {
  @view-transitions {
    direction: backward;
  }
}
```

When clicking a link with the class `.previous` for example, the upcoming cross-document transition’s `direction` would be set to `backward`.

This pseudo would also offer an answer to https://github.com/w3c/csswg-drafts/issues/8209#issuecomment-1693548146, so that you could use it to set some `view-transition-name` on the fly. Two birds, one stone.
</details>

---

With same-document navigations being taken care of by requiring authors to set `to`/`from`/`direction` params when calling `document.startViewTransition`, and cross-document-navigation setting these automatically, responding to such a type of transition happens in the same manner for both: look at the values, irrelevant of what navigation it was.

In CSS this could be an pseudo _(as already suggested in this thread)_ or an at-rule _(as also suggested in this thread)_. Personally I’m leaning towards an at-rule.

_(Note that this at-rule to respond to a VT `@view-transition` – not to be confused with `@view-transitions` which configures VTs.)_

```css
@view-transition (from: video-overview to: video-detail) or (from: video-archive to: video-archive direction: forward) {
  ::view-transition-old(content) {
     animation-name: slide-out-to-left;
  }
  ::view-transition-new(content) {
     animation-name: slide-in-from-right;
  }
}

@view-transition (from: video-detail to: video-overview) or (from: video-archive to: video-archive direction: backward) {
  ::view-transition-old(content) {
     animation-name: slide-out-to-right;
  }
  ::view-transition-new(content) {
     animation-name: slide-in-from-left;
  }
}
```

<details>
<summary>Sidetracking here: maybe there would need to be a way to set some things up on the from and to page?</summary>

Maybe like this?

```css
@view-transition (from: video-overview to: video-detail) {
  @view-transition :from {
    /* Set up some view-transition-names on the from page here, if needed */
  }

  @view-transition :to {
    /* Set up some view-transition-names on the to page here, if needed */
  }
}
```

Or like this?

```css
@route video-overview {
  /* CSS specifically targeting the video-overview route */
}

@route video-detail {
  /* CSS specifically targeting the video-detail route */
}
```

Anyway, this can be tackled later, as authors can add classes/ids/attributes to their pages and respond to that

```css
html[page-type="video-overview"] {
  /* CSS specifically targeting the video-overview route */
}
html[page-type="video-detail"] {
  /* CSS specifically targeting the video-detail route */
}
```
</details>

---

I think this proposal ticks a few boxes:

- Don’t break what has already shipped
- Same animation CSS for MPA / SPA
- Opt-in/opt-out via CSS
- Ability to respond to directionality of links _(e.g. following a link from articles list page 2 to page 3 vs from page 2 to page 1; or when clicking the back button of the browser)_
  - Note that a navigation can go forward but the directionality of the transition should go backward. _(e.g. when following a pagination link from page 2 to page 1)_
- Ability to take originator of the VT into account _(i.e. respond to which link was clicked in the list)_

This forms an answer to:

- https://github.com/w3c/csswg-drafts/issues/8685
- https://github.com/w3c/csswg-drafts/issues/8784
- https://github.com/w3c/csswg-drafts/issues/8683
- https://github.com/w3c/csswg-drafts/issues/8925
- This issue

---

What this proposal does not cover are transitions that are not between two pages, i.e. in-page transitions. Think of a page that reorders a set of elements: it can use a View Transition without a navigation happening. For that case I think it’s perfectly fine to ask of authors to use existing methods such as adding a `className` on the transition root if they want to express some type of directionality. After all, they are already relying on JavaScript to do the reordering.

```js
document.documentElement.classList.add('reordering');

const transition = document.startViewTransition(() =>
  filterAndReorderElements(filter);
);

try {
  await transition.finished;
} finally {
  document.documentElement.classList.remove('reordering');
}
```

```css
html.reordering {
  …
}
```

Alternatively authors can set from to have a value that is not covered by any route, simply to have a hook to hook onto from within their CSS. Admittedly, this is pretty hacky …

```js
document.startViewTransition({
  from: 'reordering',
  updateCallBack: () => { … },
});
```

```css
@view-transition (from: reordering) {
  /* Weird, but it works … */
}
```

---

Congrats on making it this far. Thanks for reading 😊

-- 
GitHub Notification of comment by bramus
Please view or discuss this issue at https://github.com/w3c/csswg-drafts/issues/8960#issuecomment-1693556455 using your GitHub account


-- 
Sent via github-notify-ml as configured in https://github.com/w3c/github-notify-ml-config

Received on Friday, 25 August 2023 15:38:43 UTC