height: 0→auto过渡无效因auto不可插值,应改用max-height动态设scrollheight并分步收起;transform:scaley()性能更优但需注意溢出、字体挤压及ios兼容性;移动端须处理:focus-within不稳定、scrollheight误读及aria-expanded同步。

为什么 height: 0 → height: auto 过渡不生效
浏览器无法对 auto 做插值计算,transition 失去像素依据,结果要么跳变、要么卡在 0 高度不动。这不是写法漏了 transition,而是属性本身不可动画。
用 max-height 实现真正可用的过渡
它可插值,且配合 overflow: hidden 能模拟“伸缩”效果。但关键不在加不加 transition,而在值是否贴合内容:
- 设死
max-height: 500px容易拖尾(收起时从 500px → 0 耗时固定,哪怕内容只高 60px)或裁剪(内容超 500px) - 安全做法是 JS 动态读取
element.scrollHeight,展开时赋值menu.style.maxHeight = menu.scrollHeight + 'px' - 收起必须分两步:先设
menu.style.maxHeight = '0px',再监听transitionend事件(检查event.propertyName === 'max-height'),最后清空内联样式menu.style.maxHeight = '' - 别用
setTimeout替代transitionend,连点中断动画后残留样式会导致下一次展开失败
transform: scaleY() 的适用场景和坑
性能比 max-height 更好,不依赖高度预估,适合纯视觉拉伸需求:
- 初始状态:
transform: scaleY(0); transform-origin: top; overflow: hidden; - 展开状态:
transform: scaleY(1); - 必须加
overflow: hidden,否则缩放过程中文字可能短暂溢出容器 - 缩放会轻微挤压字体,在高 DPI 屏或对渲染敏感的 UI 中需实测;iOS Safari 下
transform-origin偶有偏移,建议加will-change: transform提前提示渲染层
移动端和可访问性里最容易断掉的三件事
动画能动 ≠ 菜单可用。以下问题常在真机测试阶段才暴露:
- 点击空白处收不起菜单:不是 JS 没绑事件,而是 iOS Safari 对
:focus-within支持不稳定,焦点离开触发器后可能直接丢失,得靠 JS 主动监听blur并延时判断 - 键盘弹出后
scrollHeight读错:布局未稳定就取值,建议延迟 100ms 再读 - 屏幕阅读器无法感知状态:JS 切换类名时,务必同步更新按钮的
aria-expanded属性,并在菜单展开后focus()第一个可交互项
真正决定丝滑感的,从来不是缓动函数选 cubic-bezier 还是 ease-out,而是 max-height 是否紧贴内容、transitionend 是否可靠触发、以及焦点是否在各种中断场景下不脱链。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











