不能直接用 height + transition,因为 height: auto 不可动画,浏览器无法在 0px 和 auto 间插值,导致跳变;应改用 max-height 模拟,配合 overflow: hidden、visibility 和 opacity 协同控制,并动态设置足够但不过量的 max-height 值。

为什么不能直接用 height + transition
因为 height: auto 不是可动画的数值,浏览器无法在 0px 和 auto 之间做插值计算,transition 会直接跳变。你看到菜单“啪”一下弹出来,就是这个原因。
必须换一条路:用 max-height 模拟高度变化,它支持从具体数值到具体数值的过渡。
-
max-height初始设为0,配合overflow: hidden隐藏内容 - 展开时设为一个「明显大于内容实际高度」的固定值,比如
500px - 过渡只声明
max-height和opacity,别写all—— 否则可能意外触发动画其他属性 - 千万别在 JS 里写
element.style.height = '200px',这会覆盖 CSS transition,动画立即失效
如何避免动画卡顿或中途截断
关键在「上限值是否够大」。如果设 max-height: 300px,但内容撑开要 320px,动画就会在 300px 处戛然而止,看起来像被硬生生掐断。
更稳妥的做法是动态计算:
立即学习“前端免费学习笔记(深入)”;
- JS 中获取元素
scrollHeight,再加一点余量(比如 +20) - 展开前设置
element.style.maxHeight = content.scrollHeight + 20 + 'px' - 收起时再设回
0,注意要等 transition 结束后才重置内联样式,否则下次展开会没效果 - 如果纯 CSS 实现,就预估一个安全值(如
600px),适用于内容高度相对固定的场景
visibility 和 opacity 怎么配合才不闪屏
visibility 本身不可动画,但它能解决「元素占位」问题;opacity 负责渐显渐隐。两者必须协同,否则会出现空白闪烁或点击穿透。
- 初始状态:
max-height: 0; opacity: 0; visibility: hidden; - 展开状态:
max-height: 500px; opacity: 1; visibility: visible; -
visibility必须和max-height同步切换 —— 它不参与transition,但要在 class 切换瞬间生效 - 不要只靠
opacity隐藏,否则不可见区域仍可点击;也不要只靠visibility,否则没有淡入淡出感
transition-timing-function 选哪个最自然
0.3s 是常用时长,但缓动函数比时长更重要。用 ease 开头太慢,用户点下去像没反应;用 linear 又太机械,像拉抽屉。
- 推荐
cubic-bezier(0.25, 0.46, 0.45, 0.94),比默认ease-out更柔和,收尾不生硬 - 避免
ease-in:开头加速太缓,尤其在移动端容易误判操作失败 - 如果菜单内容多、DOM 深,建议把
transition加在transform上(如scaleY),性能更好,但需额外处理布局影响
真正难的不是写几行 CSS,而是让 max-height 的上限值既够用又不过量 —— 小了动画中断,大了收起时有延迟感。多数人卡在这一步,而不是不会写 transition。


















