I have a NextJS app which renders a list of blocks as links - when the route changes the relevant block should move to the right of the screen, changing size and position.
I'm using framer-motion's layout property to handle this, and it works as expected unless the page has been scrolled, where framer seems to be ignoring the viewport scroll, and treating the element as if it is animating from its original position relative to the top of the page.
Here's a demo codesandbox set up to reproduce this:
- Without scrolling, click on the first card. It will animate correctly.
- Now go back, scroll to the bottom and click on the last card. This time, the card will animate up from below the screen, instead of from it's position within the viewport window.
Is there a way that I can either factor in the scroll distance, or that the element's position is calculated relative to the viewport and not the top of the page?
Example:

Likely it's caused by the fact that when you change route, the new route has a smaller viewport. I don't think this is the best approach, but in my opinion, we could just save the body height of the card list page, then use that height as minimum height of the card detail page, and then remove the minimum body height once the layout animation finishes:
First, wrap the
<Link>component to a custom component<CardRedirector>:Inside
<CardRedirector>, we can adduse clientso that we can attach a click listener, and we add a click listener to save current body height and add it as the minimum body height, this will happen when the link is clicked:Then in the card detail page, we can wrap the
<Block>to<BlockContainer>component, so that we can adduse clientand add event listeneronLayoutAnimationCompleteto it. This event listener will remove the bodymin-heightproperty when the animation ends:Then change the card detail page to:
Forked sandbox: