transition不能直接作用于height:0↔auto,因auto无具体像素值导致插值失败;应改用max-height配合overflow:hidden,并通过css类切换控制显隐,避免js内联样式干扰动画。

transition 不能直接作用于 height: 0 ↔ auto
这是最常卡住的地方:很多人写 height: 0 → height: auto 并配 transition: height 0.3s,结果动画不生效。因为浏览器无法计算 auto 的具体像素值,transition 就失去了插值依据。
实操建议:
- 改用
max-height替代height,设一个「明显大于内容实际高度」的固定值(比如max-height: 500px),再配合overflow: hidden - 起始状态:
max-height: 0; opacity: 0; visibility: hidden; - 展开状态:
max-height: 500px; opacity: 1; visibility: visible; - 过渡只加在
max-height和opacity上,visibility不参与 transition(它只能立即切换)
菜单 DOM 结构要支持 CSS 控制显隐状态
纯 CSS 实现必须让展开/折叠动作能触发 class 切换,不能依赖 JS 操作内联样式——否则 transition 会被打断。
常见错误现象:JS 直接改 element.style.height = '200px',导致 transition 失效。
实操建议:
- 用
<input type="checkbox" id="menu-toggle">配合<label for="menu-toggle"></label>模拟开关,避免 JS - 菜单容器用
<div class="menu-panel">,通过 <code>#menu-toggle:checked ~ .menu-panel控制样式 - 如果必须用 JS,只负责 toggle 一个 class(如
is-open),所有动画逻辑留在 CSS 里 - 优先用
cubic-bezier(0.25, 0.46, 0.45, 0.94)(类似ease-out但更柔和) - 避免
ease-in:开头太慢,用户会误以为没响应 - 慎用
all 0.3s:可能意外过渡到不需要动画的属性(比如color),应明确列出:transition: max-height 0.3s cubic-bezier(...), opacity 0.3s - 给
label加cursor: pointer和足够 padding(至少 44×44px 符合移动端触控规范) - 隐藏 checkbox 用
position: absolute; opacity: 0; width: 1px; height: 1px;,别用display: none(会脱离可访问树) - 为键盘用户提供视觉反馈:
.menu-panel:focus-within { outline: 2px solid #007bff; }
transition-timing-function 影响体验比时长更关键
0.3s 是常用时长,但用 ease 或 linear 会让菜单“弹”或“拖”,用户感知生硬。
实操建议:
移动端点击区域与 focus 状态容易被忽略
在触摸设备上,label 的点击热区若太小,或 checkbox 被 display: none 后未正确关联,会导致点不动;键盘用户按 Tab 进入菜单时,若没处理 :focus-within 或 :focus-visible,可访问性就断了。
实操建议:
max-height 的取值、visibility 的时机、以及 focus 状态是否真正可达。这些地方一松动,平滑就变成卡顿或不可用。











