Framer Motion:如何使外部div随AnimatePresence退出动画平滑过渡高度?
问题解决:Framer Motion 实现外层容器高度平滑过渡
你遇到的问题是列表元素退出时,外层fit-content高度的容器直接跳变,这是因为普通div无法感知子元素的动画过程,只能在元素完全移除后更新高度。用下面的方法可以解决:
核心方案:用 Framer Motion 的外层容器 + 布局动画
把外层的普通<div>换成<motion.div>,并添加layout属性,让它自动跟踪子元素的布局变化,生成平滑的高度过渡动画。同时优化子元素的退出动画配置,确保容器能正确捕捉尺寸变化。
修改后的代码示例
<motion.div style={{ height: 'fit-content', backgroundColor: 'black' }} layout transition={{ layout: { type: 'spring', damping: 20, stiffness: 300 } }} > <AnimatePresence mode={'wait'}> {items.map((id) => ( <motion.div key={id} layout exit={{ opacity: 0, height: 0, margin: 0 }} transition={{ opacity: { duration: 0.3 }, layout: { type: 'spring' } }} > <Item key={id} /> </motion.div> ))} </AnimatePresence> </motion.div>
关键细节说明
- 外层
motion.div加layout:Framer Motion会自动计算子元素变化前后的容器尺寸,生成平滑的高度过渡动画,不需要手动写height的关键帧。 - 子元素退出动画补充
height:0和margin:0:让元素在淡出的同时逐步收缩自身尺寸,外层容器能实时感知到高度变化,避免跳变。 - 修正key值:不要用
-id这种可能导致重复的key,直接使用item的唯一标识,确保React能正确识别元素的添加/移除动作。 - 拆分transition配置:可以给透明度动画和布局动画分别设置参数,让淡出和高度变化的节奏更协调。
如果不想用Framer Motion,也可以用CSS的max-height过渡,但需要预估列表项的最大高度,灵活性不如Framer Motion的方案:
.container { transition: max-height 0.5s ease; max-height: 1000px; /* 设为足够大的值 */ overflow: hidden; } .container.shrinking { max-height: 0; }
但这种方法需要手动控制类名切换,不如Framer Motion的自动布局动画方便。
内容的提问来源于stack exchange,提问作者Parker Hall
相关产品推荐
相关产品推荐

