height: 0 → height: auto 无法触发 transition 动画,因浏览器无法对 auto 值做数值插值;应改用 max-height: 0 → max-height: 500px(需大于最大内容高度),配合 overflow: hidden、opacity 和 visibility 控制显隐,并仅对 max-height 和 opacity 设置 transition。

不能直接用 height: 0 → height: auto 配 transition,动画一定失效。必须换思路。
为什么 height: 0 到 height: auto 不动效
浏览器无法对 auto 做数值插值——transition 需要起止两个确定像素值才能逐帧计算中间状态。写 height: auto 相当于告诉浏览器“你看着办”,它没法“看着办”出过渡帧。
- 常见错误现象:
transition: height 0.3s+height: 0/height: auto,结果菜单瞬间闪现或完全不动 - 真正生效的路径只有:固定值 → 固定值(比如
max-height: 0→max-height: 500px) - 选
500px是经验值:得明显大于菜单最大可能高度(含 padding、line-height),但别过大(影响重排性能)
用 max-height 替代 height 的实操要点
这是最轻量、兼容性最好、无需 JS 的方案,核心是借 max-height 的可动画性 + overflow: hidden 配合隐藏溢出内容。
- 初始状态:
max-height: 0+overflow: hidden+opacity: 0+visibility: hidden - 展开状态:
max-height: 500px+opacity: 1+visibility: visible -
visibility不参与transition(它只能立即切换),所以只对max-height和opacity写过渡:transition: max-height 0.3s cubic-bezier(0.25, 0.46, 0.45, 0.94), opacity 0.3s - 别用
all 0.3s:万一菜单里有color或font-size变化,会意外触发无关动画
JS 控制时,只操作 class,别碰 style.height
哪怕你用 JS 触发展开,也绝不要写 el.style.height = '200px'——这会覆盖 CSS 中定义的 transition,动画直接报废。
立即学习“前端免费学习笔记(深入)”;
- 正确做法:只调用
el.classList.toggle('is-open'),所有样式和过渡逻辑全留在 CSS 里 - 如果用 checkbox 模拟开关(纯 CSS 方案),确保
<input type="checkbox">用position: absolute; opacity: 0; width: 1px; height: 1px;隐藏,而非display: none(否则屏幕阅读器不可见) - 移动端点击热区至少 44×44px,给关联的
<label>加cursor: pointer和足够padding
cubic-bezier() 比时长更影响体验
0.3s 是合理时长,但缓动函数选错,用户会觉得“卡”或“拖”。默认 ease 开头太慢,结尾又太急;linear 则全程匀速,缺乏自然感。
- 推荐用
cubic-bezier(0.25, 0.46, 0.45, 0.94):类似 ease-out,但起始响应更快,收尾更柔和 - 绝对避免
ease-in:开头延迟明显,用户点完没反应,容易连点两次 - 如果菜单内容多、DOM 深,
max-height设太高(如 2000px)会导致动画末段明显减速——这是浏览器插值计算导致的视觉误差,不是 bug
真正难的不是写几行 transition,而是判断该用 max-height 还是 transform:前者适合垂直下拉(内容高度不确定),后者适合侧滑/缩放(位移/尺寸确定)。选错就白调半天。


















