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

Design an API for the MPA transition #2

Open
vmpstr opened this issue Nov 11, 2020 · 12 comments
Open

Design an API for the MPA transition #2

vmpstr opened this issue Nov 11, 2020 · 12 comments
Labels
api-shape Feedback regarding API shape.

Comments

@vmpstr
Copy link
Collaborator

vmpstr commented Nov 11, 2020

The SPA transition case has a working API, but it's unclear what the MPA equivalent should look like.

We need to design that

@vmpstr
Copy link
Collaborator Author

vmpstr commented Apr 26, 2021

I think we still need a prepare step, so that should remain the same. However, the start call should be replaced with something like

startOnNavigation(url, sharedElements: selectors);

I think we would want to pass the url here, which would initiate the navigation and sharedElement selectors will need to be a list of identifiers that can be used to identify elements on the destination page.

It's unclear whether these elements should be specially tagged (ie opt-in style, something like sharedID = "foo") or just rely on regular css selectors.

One thing to note is that for SPA, we require paint containment right now, and I think we need that for the MPA case as well.

/cc @jakearchibald

@jakearchibald
Copy link
Collaborator

jakearchibald commented Apr 26, 2021

If possible, I think we should avoid triggering the navigation with a new API. There are lots of ways to navigate, some get special privileges, and some modify history state in a particular way. If we create a new API we'll likely lose some of those, or end up with an option bag to try and cover all of those cases.

https://github.com/WICG/app-history has a "navigate" event, which sounds like exactly what we'd need.

It's unclear whether these elements should be specially tagged (ie opt-in style, something like sharedID = "foo") or just rely on regular css selectors.

This makes me wonder if the MPA API would be better in CSS:

@nav-transition {
  type: reveal;
  duration: 300ms;
}

.main-avatar {
  nav-transition-id: main-avatar;
}

.header {
  nav-transition-id: header;
}

Setting nav-transition-id could also enforce other CSS requirements, like paint containment.

Then, when the next page is ready to go, the browser figures out which nav-transition-id elements have an equivalent on each page, and perform the transition.

I'm not sure how you'd specify different nav transitions for different destinations. Maybe you could do that with JS in the "navigate" event. Or, something like:

@nav-transition {
  type: reveal;
  duration: 300ms;
  destination: url-prefix('/profile/');
}

…where the first @nav-transition block with the matching destination is used.

One thing to note is that for SPA, we require paint containment right now, and I think we need that for the MPA case as well.

That seems ok, but what's the reason for the requirement?

@jakearchibald
Copy link
Collaborator

Some feedback I got: The 'destination' should be part of the @-rule. We also need to consider how the inclusion of a URL might make it harder to deliver these transitions in the form of a library.

@bramus
Copy link
Contributor

bramus commented Jun 9, 2021

@jakearchibald (thinking out loud here) How about some generic keywords such as forwards / backwards? Or perhaps allowing '*' inside url-prefix()? Or support for dynamic segments in url-prefix() (often used syntaxes being ":id" an "{id}")?

@daKmoR
Copy link

daKmoR commented Oct 6, 2021

Am I right to assume that nav-transition-id is used to identify the "shared" elements?

considering the following example

<!-- index.html -->
<html>
  <style>
    header {
      nav-transition-id: header;
      height: 100px;
    }
    main {
      nav-transition-id: main;
      background: #ccc;
    }
  </style>
  <body>
    <header>
      <a href="index.html">Home</a>
      <a href="red.html">Red</a>
      <a href="blue.html">Blue</a>
      <a href="about.html">About</a>
    </header>
    <main>
      <h1>Home Page</h1>
    </main>
  </body>
</html>

<!-- red.html & blue.html (only h1 text content is different) -->
<html>
  <style>
    header {
      nav-transition-id: header;
      height: 30px;
    }
    main {
      nav-transition-id: main;
      background: red;
    }
  </style>
  <body>
    <header>
      <a href="index.html">Home</a>
      <a href="red.html">Red</a>
      <a href="blue.html">Blue</a>
      <a href="about.html">About</a>
    </header>
    <main>
      <h1>Red Page</h1>
    </main>
  </body>
</html>

<!-- about.html -->
<html>
  <style>
    .fancy-about-page {
      /* ... */
    }
  </style>
  <body>
    <div class="fancy-about-page">
      <h1>About</h1>
      <p>...</p>
    </div>
    <header>
      <a href="index.html">Home</a>
      <a href="red.html">Red</a>
      <a href="blue.html">Blue</a>
      <a href="about.html">About</a>
    </header>
    <main>
      <h1>Blue Page</h1>
    </main>
  </body>
</html>

I would expect the following transitions to happen

Transition Header Height Transition Main Background Transition Full Transition (no shared elements)
Home -> Red
Home -> Blue
Home -> About
Red -> Home
Red -> Blue
Red -> About
Blue -> Home
Blue -> Red
Blue -> About
About -> Home
About -> Red
About -> Blue

Is this a right assumption?

@nickcoury
Copy link

nickcoury commented Oct 7, 2021

A few things that would be nice to have in this API:

  1. Separate concepts of exit and enter animations.

One reason for using a SPA and animating transitions is to make apps feel immediately responsive. If I'm understanding this proposal, it would wait until the next page is ready to execute .start()/.startOnNavigation() since it requires the next page's elements to animate.

What would be nice is a two-phase animation. Allow .exitAnimation() to run immediately when the next page is requested, which could allow any of the shared elements to be animated immediately. For example, slide in a header, slide a shared element from its current location to its expected location on the next page, or show a loading spinner/ghost card. Ideally with enough control to specify their positions, transforms, easing curves, etc. as suggested here.

Then, a second .enterAnimation() will be called once the next page is rendered enough to load. This could still look close to the proposed API, but using the shared elements as positioned in the exit animation. This still allows animations to the final positions easily.

  1. Additional control of the render timeline.

If elements are being animated between both pages, the ideal case would be to finish the transition as soon as all shared elements are available. If the transition is too early, animations may look terrible if some shared elements aren't rendered yet. If we wait until the entire page is rendered, it may add a lot of latency and make SET for MPA feel slow.

Perhaps something like renderblocking could be extended to work on elements in the body chunk and used here?

Another improvement to the timeline would be to add an additional hook .beforeEnterAnimation() that would run once the destination page is being received, but before it is rendered. This would be a small window, but if an intermediate animation could happen on the GPU to animate the shared elements one additional time, it might significantly improve the user experience. For example, the header sliding in mentioned in .exitAnimation() could happen during this phase instead, and the loading spinner removed. That provides better visual feedback and perceived responsiveness for users.

@nickcoury
Copy link

Another aspect that is not clear for MPAs is back/forward button navigations. Is there an option to run these animations on subsequent navigations? It might require providing an inverse configuration for the reverse direction. It could also get complicated if the page itself changes before it is re-run, but overall I think the API would be able to be saved and re-executed if needed.

@khushalsagar
Copy link
Collaborator

We were already thinking about entry/exit animations in the context of #37 but your suggestion is more about the timeline on which these animations run. Our current approach is to run all animations on the new Document's timeline once it is ready for first render. While the idea you're proposing is to run some animations at 2 other stages : on the old page once the navigation is initiated and on the new page (using cached content from the old page?) while the new page is being received.

Regarding extending renderblocking to include elements in the body chunk. Not sure how yet but we do need a way to know that all shared elements necessary for animations post first render have been fetched.

@khushalsagar
Copy link
Collaborator

And to your point about back/forward navigations, this came up in issue #25 as well. And as you mentioned this gets complicated if the new page changes before the back navigation.

Our thinking here is that the developer should be able to configure the transition for a back navigation. app-history would provide a good hook to know when a back navigation is initiated and configure based on current state of the new page.

@daKmoR
Copy link

daKmoR commented Nov 2, 2021

anything we can do to help out here?

@Pyrolistical
Copy link

Pyrolistical commented Jun 30, 2022

Isn't there a large overlap with MPA transitions and <portal>s? https://web.dev/hands-on-portals/

I know its not exactly the same thing as being able to carry the same element across MPA boundaries, but you can fake it with <portals>.

It's better to have two independent proposals that compose than to have redundant effort.

@jeremyroman
Copy link

I agree, and in fact many of us working on both proposals sit in the same room. I think an API for shared element transitions between pages makes sense, even though there may be some overlap with portals.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
api-shape Feedback regarding API shape.
Projects
None yet
Development

No branches or pull requests

8 participants