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

I wanted to present the 3 ways I think we can go about this. Seems like the discussions are bouncing around between these 3, and we need to choose a strategy. To do this, I'm going to take a use case that's a little above simple, and represents an experience that resembles what early adopters have been doing, and show how this would be implemented using the 3 options.

The use case is as follows:
-  main pages: /home, /list, /cart, /product
- for any of these page transitions: slide from right
- but if using back navigation: slide from left
- (/list|/cart)<->/product: also animate product picture
 - in addition, internal sections in the page can be reordered using a VT animation.

The options on how to qualify a transition are as follows:
1. single-ident transition type
2. A dictionary of parameters
3. Purely navigation-oriented

All the options would have these routes defined:
```css
        @routes {
            --home: urlpattern(/((home/?)?)?*);
            --cart: url(/cart);
            --list: urlpattern(/list\/*);
            --product: urlpattern(/product/:id);
            --main-page: urlpattern(/(home|cart|list)?\/*);
        }
```

## Option 1: single-ident `view-transition-type`

```css
        @navigation --main-page to --main-page {
            view-transition-behavior: trigger;
            view-transition-type: slide-from-right; 
        }

        @navigation back from --main-page to --main-page {
            view-transition-type: slide-from-left; 
        }

        @navigation (--list, --product), (--cart, --product) {
            view-transition-type: slide-from-right-with-product-picture;
        }

        @navigation back (--list, --product), back (--cart, --product) {
            view-transition-type: slide-from-left-with-product-picture;
        }

        html:active-view-transition(slide-from-right),
        html:active-view-transition(slide-from-right-with-product-picture) {
            &::view-transition-group(root) {
                animation-name: slide-from-right;
            }
        }
        html:active-view-transition(slide-from-left),
        html:active-view-transition(slide-from-left-with-product-picture) {
            &::view-transition-group(root) {
                animation-name: slide-from-left;
            }
        }
        html:active-view-transition(slide-from-left-with-product-picture),
        html:active-view-transition(slide-from-right-with-product-picture) {
            #product-picture {
                view-transition-name: product-pic;
            }
        }

        html:active-view-transition(reorder) {
            #section1 { view-transition-name: section1; } 
            #section2 { view-transition-name: section2 } 
            #section3 { view-transition-name: section3; } 
        }

```

```js
        function navigate(newURL, isBack) {
            document.startViewTransition({
                updateCallback: () => do_navigate(newURL, isBack),
                viewTransitionType: ViewTransition.getTypeFromNavigation({
                    oldURL: location.href,
                    newURL,
                    direction: isBack ? "back" : "forward"
                });
            })
        }

        function reorder() {
            document.startViewTransition({
                updateCallback: () => do_reorder(),
                viewTransitionType: "reorder"
            });
        }
```

This feels simple to implement, however it requires a lot of permutations to create idents that cover all the cases.

## Option 2: parameter dictionary

```css
        @navigation --main-page to --main-page {
            view-transition-behavior: trigger;
            --main-page-slide: left; 
        }

        @navigation back from --main-page to --main-page {
            --main-page-slide: right;
        }

        @navigation (cart, product), (list, product) {
            --list-to-product: yes;
        }

        html:active-view-transition(--main-page-slide: left)::view-transition-group(root) {
            animation-name: slide-from-left;
        }
        html:active-view-transition(--main-page-slide: right)::view-transition-group(root) {
            animation-name: slide-from-left;
        }

        htnk:active-view-transition(--list-to-product) {
            #product-picture { 
                view-transition-name: product-pic;
            }
        }

        html:active-view-transition(reorder) {
            #item1 { view-transition-name: item1; } 
            #item2 { view-transition-name: item2; } 
            #item3 { view-transition-name: item3; } 
        }

```

```js
        function navigate(newURL, isBack) {
            document.startViewTransition({
                updateCallback: () => do_navigate(newURL, isBack),
                viewTransitionParams: ViewTransition.getParamsFromNavigation({
                    oldURL: location.href,
                    newURL,
                    direction: isBack ? "back" : "forward"
                });
            })
        }

        function reorder() {
            document.startViewTransition({
                updateCallback: () => do_reorder(),
                viewTransitionType: "reorder"
            });
        }
```

This feels more compact, however adds a level of indirection that might feel verbose for simple cases.
## Option 3: navigation oriented


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

    html {
        :active-view-transition(from --main-page to --main-page) {
            &::view-transition-group(root) {
                animation-name: slide-from-right;
            }
        }
        :active-view-transition(back from --main-page to --main-page) {
            &::view-transition-group(root) {
                animation-name: slide-from-left;
            }
        }
        :is(active-view-transition(--product, --list), active-view-transition(--product, cart)) {
            #product-picture {
                view-transition-name: product-picture;
            }
        }
    }
```

```js
        function navigate(newURL, isBack) {
            document.startViewTransition({
                updateCallback: () => do_navigate(newURL, isBack),
                navigation: {
                    oldURL: location.href,
                    newURL,
                    direction: isBack ? "back" : "forward"
                }
            })
        }

        function reorder() {
            document.documentElement.classList.toggle("reordering", true);
            document.startViewTransition({
                updateCallback(): () => {
                    document.documentElement.classList.toggle("reordering", false);
                }
            });
        }
```

This seems much more compact, however it means that transition types don't work for element-scoped transitions, and also that for transitions that are not URL-based (like reordering in this case) would need to use the "old" mechanism of toggling classes on the root element.



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


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

Received on Tuesday, 22 August 2023 17:26:47 UTC