details标签默认不支持height过渡动画,需用max-height配合overflow: hidden实现平滑展开/收起,通过details[open]伪类控制,并注意兼容性、焦点管理及javascript补足。

details标签默认没有动画,CSS transition不生效
直接给 details 加 transition: height 0.3s 没用——因为 details 是替换元素(replaced element),其内部高度由浏览器控制,且 height 在展开/收起时不是连续变化的,而是从 auto 切换到具体像素或反之,而 auto 无法被 transition 动画。
真正能动的是 summary 后面的匿名内容块(即 details 的可折叠内容),但这个块没有标签名,得靠 <details> > *</details> 或 <details> :not(summary)</details> 选中。不过更稳妥的方式是手动包裹一层 <div class="details-content">。
<ul>
<li>必须显式设置 <code>height 或 max-height 才能触发 transition
max-height 更实用:收起时设为 0,展开时设为足够大的值(如 500px),避免计算真实高度overflow: hidden,否则内容会溢出summary 不需要加 transition,它本身不参与高度变化用 max-height 实现平滑展开/收起
这是目前最可靠、兼容性好(Chrome 12+、Firefox 117+、Safari 17.4+)的做法。关键在于利用 :has(> summary:not([open])) 或 JavaScript 控制类名,但纯 CSS 方案需依赖 details[open] 伪类。
details[open] .details-content {
max-height: 500px;
opacity: 1;
transition: max-height 0.3s ease-out, opacity 0.2s ease-in;
}
.details-content {
max-height: 0;
opacity: 0;
overflow: hidden;
transition: max-height 0.3s ease-in, opacity 0.2s ease-out;
}
注意:max-height 值要大于内容实际高度,否则会截断;如果内容高度差异大,可设为 100vh,但需防极端长内容导致性能抖动。
JavaScript 补足 Safari 旧版本和动画完成回调
Safari 16.4 之前不支持 details[open] 的 CSS 过渡,且所有浏览器都不提供“动画结束”事件,比如你想在收起后移除 DOM 或触发动画链,就得监听 toggle 事件 + setTimeout 模拟。
- 用
details.addEventListener('toggle', () => { ... })比监听click更准确(支持键盘空格/回车触发) - 动画时间与 JS 中的
setTimeout要对齐,比如 CSS 设了0.3s,JS 就用setTimeout(fn, 300) - 避免在
toggle里直接操作offsetHeight,会强制同步重排,建议用getComputedStyle或 requestAnimationFrame - 若需逐项动画多个
details,别用querySelectorAll('details')+forEach绑定,改用事件委托
移动端点击穿透与 focus 状态干扰
在 iOS Safari 上,summary 默认有 user-select: none,但快速连点可能触发两次 toggle,看起来像“闪一下”。另外,展开后焦点仍停留在 summary,键盘用户按 Tab 会跳过内容区。
- 加
summary:focus { outline: none; }前,先确保有替代焦点样式(比如背景色或边框),否则可访问性受损 - 展开后用
details.querySelector('.details-content').setAttribute('tabindex', '-1')并.focus(),让键盘流自然进入内容 - 防止点击穿透:不要给
summary加pointer-events: none,那会让整个交互失效;真要拦截,用event.stopPropagation()在父容器上 - Android Chrome 有
details点击延迟问题,可加touch-action: manipulation到summary
max-height 的上限值要覆盖所有可能内容,且每次动态增减内容后,若高度变化大,得重置 max-height 再触发 transition —— 这时候就得上 JS 了。











