max-height 是最实用的过渡方案,因 height: auto 无法计算过渡值,而 max-height 支持数值过渡且设为 30rem 或 400px 可兼顾显示与动画效果;必须配合 overflow: hidden 防止内容外溢,并注意 label 绑定、点击区域和过渡时长(0.25–0.35s 最佳)。

为什么 max-height 是最实用的过渡方案
直接对 height 做 transition 无效——因为 height: auto 无法被浏览器计算出过渡起止值。用 max-height 替代是业内通用解法:它支持数值过渡,且设得足够大时不影响内容显示。
关键点在于取值要合理:max-height 不能太小(否则内容被截),也不宜过大(否则动画过长)。常见做法是预估最大内容高度(比如 500px),或用 JS 动态设,但纯 CSS 场景下建议保守取 30rem 或 400px —— 大多数折叠面板够用,动画时长也自然。
overflow: hidden 必须配合使用
没有 overflow: hidden,max-height 过渡时内容会“撑开”容器并外溢,视觉上就是突然弹出、毫无平滑感。这个声明必须加在被折叠的容器上(通常是 .accordion-content)。
注意两个易错点:
立即学习“前端免费学习笔记(深入)”;
- 别加在父级标题(
.accordion-header)上,否则点击区域可能失效 - 如果内容里有
position: absolute元素,它们可能逃逸出overflow: hidden范围,需额外用transform: translateZ(0)或contain: layout触发新层叠上下文
如何用 :checked + ~ 实现无 JS 切换
纯 CSS 手风琴依赖隐藏的 <input type="checkbox"> 或 <input type="radio">,通过 :checked 状态控制后续兄弟元素的 max-height。
结构要点:
- 把
<input>放在标题前,并用position: absolute; opacity: 0隐藏,保留可访问性 - 标题用
<label for="id"></label>关联该 input,点击即触发状态切换 - 内容区用
input:checked ~ .accordion-content选择器匹配,设置max-height: 30rem - 初始状态设
max-height: 0和opacity: 0(后者可选,增强收起感)
示例片段:
<input type="checkbox" id="acc-1">
<label for="acc-1">标题</label>
<div class="accordion-content">内容...</div>
#acc-1:not(:checked) ~ .accordion-content {
max-height: 0;
opacity: 0;
transition: max-height 0.3s ease-out, opacity 0.2s ease-out;
}
#acc-1:checked ~ .accordion-content {
max-height: 30rem;
opacity: 1;
}
移动端点击区域和可访问性不能忽略
纯 CSS 方案在移动端容易误触或响应迟钝,根源常是点击目标太小或 label 绑定失效。
务必检查:
-
label的for属性是否与input的id完全一致(大小写、连字符都不能错) - 给
label加cursor: pointer和足够内边距(至少padding: 12px),避免 iOS Safari 因点击热区过小而忽略事件 - 为
input保留focus样式(如outline),键盘用户 Tab 导航时才不会迷失
过渡时间别设太长——超过 0.4s 就会觉得卡顿;但也不能低于 0.2s,否则动画像抽搐。0.25–0.35s 是手感最稳的区间。


















