ehrencrona
ehrencrona

Reputation: 7002

View transitions and scroll restoration

I've noticed some odd behaviors with view transitions and scroll restoration in Chrome and I'm trying to understand if these are bugs or it is intended behavior. I can't find any official information on how they are supposed to behave in combination with scrolling.

I've created a fiddle that emulates an SPA with two pages: one with a small blue ball at the end of the page and one with a large blue ball at the top of the page.

If I

Chrome will

That it first restores the scroll position before starting the animation results in a discontinuity in the animation that IMO completely destroys the point of it.

Am I doing something wrong, e.g. is there something wrong with how I do the SPA functionality, or is this a Chrome bug, or is it intended behavior?

--

This is the code:

let page = 0;

function render() {
  let body = '';

  if (page == 0) {
    for (let i = 0; i < 13; i++) {
      body += `<p>.</p>`;
    }

    body += `<div style="height: 30px; width: 30px; border-radius: 100%; background-color: blue; view-transition-name: bar"></div>`
  } else {
    body += `<div style="height: 300px; width: 300px; border-radius: 100%; background-color: blue; view-transition-name: bar"></div>`

    for (let i = 0; i < 13; i++) {
      body += `<p>.</p>`;
    }
  }


  document.querySelector('#content').innerHTML = body;
  document.querySelector('a').innerHTML = page == 0 ? 'Next' : 'Back';
}

render();

const useViewTransitions = true;

function transition() {
  if (useViewTransitions) {
    document.startViewTransition(render);
  } else {
    render();
  }
}

document.querySelector('a').addEventListener("click",
  async function(event) {
    event.preventDefault();

    if (page == 0) {
      page++;

      history.pushState({
        page
      }, '');

      transition();
    } else {
      history.back();
    }
  }
);

window.addEventListener("popstate", ({
  state
}) => {
  page = state ? .page || 0;

  transition()
})

with the following HTML

<div style="height: 30px; width: 30px; border-radius: 100%; background-color: red"></div>

<div id="content">
</div>

<a href="#"></a>

--

I hope the above description was comprehensible. Unfortunately I can't post a video, but this is the instant before I press back on page two (scrolled to the top of the page):

enter image description here

And this is an instant later when it scrolls me down before starting the animation

enter image description here

Upvotes: 2

Views: 1055

Answers (1)

Alexander Early
Alexander Early

Reputation: 11

I ran into a similar problem with a view transition that involved a scroll. My solution was to defer slightly at the beginning and end of the transition function, e.g.

document.startViewTransition(async () => {
  await 1;

  updateDOM();
  window.scrollTo({top: scrollY});
  
  await 1;
})

I think there is a slight race condition between creating the snapshot for the transition and setting the scroll position.

Upvotes: 1

Related Questions