Framer Motion在Next.js中marginTop动画仅单向生效问题
导航栏开合动画单向生效问题修复
问题场景
尝试为导航栏实现开合动画:外层容器通过改变高度实现动画,内层容器向下滑动。但动画仅单向生效——导航栏关闭时向上滑动动画正常,打开时无任何动画效果。
现有代码
const innerVariants = { open: { marginTop: "0", }, closed: { marginTop: "-100vh", }, };
<motion.div initial={false} variants={innerVariants} animate={isOpen ? "open" : "closed"} transition={{ duration: 0.5 }} style={{ height: "100vh" }} > </motion.div>
错误提示
你正尝试将marginTop从"-100vh"动画过渡到"0vh"。-100vh不是可动画的值——要启用此动画,请通过
style属性将-100vh设置为可与0vh过渡的动画值。
问题原因
Framer Motion的动画引擎无法正确解析-100vh这类带相对单位的字符串值作为动画起始/结束状态。关闭动画时(从0到-100vh)引擎可能做了隐式转换,但反向触发时(从-100vh到0)无法识别数值变化逻辑,导致动画失效。
解决方案
方案1:修复marginTop动画兼容性
将状态值统一为可解析的格式,同时通过style属性同步初始状态,确保动画引擎能识别数值变化:
const innerVariants = { open: { marginTop: 0, // 使用数值类型替代字符串"0" }, closed: { marginTop: "-100vh", }, };
<motion.div initial={{ marginTop: "-100vh" }} // 显式声明初始状态 variants={innerVariants} animate={isOpen ? "open" : "closed"} transition={{ duration: 0.5 }} style={{ height: "100vh", marginTop: isOpen ? 0 : "-100vh" }} // 通过style同步静态值 > </motion.div>
方案2:改用translateY实现动画(推荐)
使用transform: translateY()替代marginTop,这是前端动画的最佳实践——transform动画不会触发浏览器重排,性能更优,且Framer Motion对transform属性的支持更稳定:
const innerVariants = { open: { y: 0, // y轴位移为0 }, closed: { y: "-100%", // 向上位移自身高度的100%,适配任意容器高度 }, };
<motion.div initial={false} variants={innerVariants} animate={isOpen ? "open" : "closed"} transition={{ duration: 0.5 }} style={{ height: "100vh" }} > </motion.div>
内容的提问来源于stack exchange,提问作者tinu24
相关产品推荐
相关产品推荐

