Next.js中Framer Motion页面转场出现页面移位问题如何解决
问题根因
这个快速移位是客户端拉取数据引发的布局偏移,和Framer Motion转场本身的逻辑没有关系:
- 用
useEffect在客户端请求Sanity数据时,页面组件第一次挂载只会渲染初始空状态或者加载态,此时页面高度由加载态内容决定 - 等Sanity接口返回数据后,组件才会替换成真实业务内容,页面高度会突然变化,这个变化刚好卡在Framer Motion入场动画的执行阶段,就会出现你看到的“快速偏移后归位”的现象
- 之前把services页改成
getServerSideProps后问题消失,本质是因为服务端会在页面渲染前就完成所有数据拉取,返回给浏览器的HTML已经是带完整数据的最终版本,页面挂载后不存在中途替换内容、高度突变的过程,自然不会有移位问题。
修复方案
按修复彻底度和改造成本从优到劣排序:
方案1(推荐)
把feeders页的客户端数据获取逻辑迁移到服务端,从根源消除布局偏移:
- 如果feeders页的内容不需要每次用户请求都拉取最新数据,优先用
getStaticProps在项目构建阶段就拉取Sanity数据生成静态页面,访问性能最好 - 如果feeders内容需要实时更新,就和services页保持一致用
getServerSideProps,每次请求时在服务端拿完Sanity数据再返回渲染好的页面
这两种方式都能保证页面组件在浏览器端挂载时,拿到的就是完整的最终数据,不会出现“加载态→真实内容”的替换过程,也就不会有高度突变引发的移位。
方案2(必须保留客户端useEffect拉数时使用)
如果业务要求必须在客户端用useEffect拉取Sanity数据,做两处调整即可消除抖动:
- 锁定页面容器基础尺寸,避免高度突变
给_app.js里包裹页面的motion.div添加min-height: 100vh、overflow-x: hidden两个样式,同时给feeders页的加载态配置和真实内容等高的骨架屏做占位,不要用尺寸远小于真实内容的转圈图标、短提示文字当加载态,保证加载态和真实内容渲染时的外层容器高度一致。 - 让Framer Motion自动兼容布局变化
给motion.div添加layout属性,Framer Motion会自动把布局尺寸的硬跳变转为平滑过渡,不会出现肉眼可见的快速移位。
修改后的_app.js核心代码如下:
function MyApp({ Component, pageProps }) { const router = useRouter(); return ( <Layout> <AnimatePresence exitBeforeEnter> <motion.div key={router.route} initial="hidden" animate="enter" exit="exit" layout // 自动处理布局尺寸变化,消除硬跳变 style={{ minHeight: '100vh', // 锁定页面最小高度,避免内容加载时撑高页面 overflowX: 'hidden' // 避免入场横向位移时触发横向滚动条,导致页面宽度变化抖动 }} variants={{ hidden: { opacity: 0, x: -200, y: 0, }, enter: { opacity: 1, x: 0, y: 0, }, exit: { opacity: 0, }, }} > <Component {...pageProps} /> </motion.div> </AnimatePresence> </Layout> ); }
内容的提问来源于stack exchange,提问作者Kacy
相关产品推荐
相关产品推荐

