transition不能直接用于height:0↔height:auto,因浏览器无法计算auto值导致动画失效;推荐用max-height替代,设足够大的固定值并配合overflow:hidden实现平滑过渡。

transition 为什么不能直接用在 height: 0 ↔ height: auto 上
直接对 height 从 0 切换到 auto 不会触发动画,因为浏览器无法计算 auto 的具体数值,transition 失效。这是风琴菜单最常卡住的地方。
解决思路是避开 height: auto,改用可被插值的值:要么预设固定高度,要么用 max-height 模拟(推荐),或者改用 transform: scaleY() + overflow: hidden。
-
max-height法最实用:设一个足够大的上限值(如max-height: 500px),再过渡max-height;展开时内容若超限会截断,所以得确保这个值大于所有子项最大高度 - 用
transform: scaleY()性能更好,但需额外处理子元素内边距、滚动等细节 - 不要给父容器设
overflow: hidden后又期望子元素出现滚动条——它会被裁掉
用 max-height + transition 实现可折叠面板
核心是把每个面板的 max-height 从 0 过渡到一个安全上限值,并配合 overflow: hidden 隐藏溢出内容。
.accordion-panel {
max-height: 0;
overflow: hidden;
transition: max-height 0.3s ease-in-out, padding 0.3s ease-in-out;
}
.accordion-panel.is-open {
max-height: 500px; /* 必须是具体数值,不能是 auto */
padding: 1rem 0;
}
- 记得同时过渡
padding或opacity,否则展开时顶部/底部留白突兀 -
ease-in-out比linear更自然;时间建议 0.25–0.35s,太长拖沓,太短像闪现 - JavaScript 控制时,先加
is-open类,再强制重排(offsetHeight)以触发过渡,否则可能跳过动画
JavaScript 如何正确触发折叠/展开
单纯切换 class 可能不触发过渡,尤其在 DOM 刚插入或初始隐藏状态下。关键是要让浏览器“看到”前后两个状态。
- 展开前先设
max-height: 0,再用offsetHeight强制重排:panel.offsetHeight;,再加is-open类 - 收起时可直接移除类,但若想更稳,先设
max-height为当前实际高度(getComputedStyle(panel).height),再设回0 - 避免用
display: none控制显隐——它会让transition完全失效;始终用max-height+overflow - 多个面板互斥?监听点击后遍历其他面板,移除
is-open类即可,无需额外计时器
移动端点击区域与可访问性容易被忽略的点
折叠菜单在手机上常点不中、响应迟钝,或屏幕阅读器读不出状态,问题多出在标记和交互细节上。
- 标题按钮必须是
<button></button>或带role="button"+tabindex="0"的元素,否则键盘不可聚焦 - 用
aria-expanded="true/false"动态更新按钮属性,屏幕阅读器靠它判断当前状态 - 移动端点击热区至少 44×44px,小图标要包一层足够大的
padding或伪元素 - 别依赖
:hover做展开逻辑——它在触摸设备上基本无效;所有状态变更必须由click或keydown(Enter/Space)触发
真正难的不是写过渡,而是让高度估算准确、重排时机刚好、语义标签到位——这三处任一出错,动画就断在半路或对辅助技术失明。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











