details 和 summary 是 html5 原生配对标签,details 为容器、summary 必为其首子元素,点击自动切换展开状态,浏览器原生管理 open 属性、aria-expanded、键盘支持及焦点;不支持 height 动画和手风琴互斥,需 js 实现。

能实现零 JS 的语义化折叠交互,但不能直接做手风琴互斥或 height 动画——这是它最常被误用的两个地方。
details 和 summary 的基础行为是什么
它们是 HTML5 原生配对标签:details 是容器,summary 必须是它的第一个子元素,点击 summary 会自动切换 details 的展开状态。浏览器原生管理 open 属性(存在即为展开),并自动添加 aria-expanded、键盘支持(空格/回车)、焦点管理。
- 不写
open属性 → 默认收起 - 加
open属性 → 默认展开:<details open><summary>...</summary></details> -
summary自带三角形指示符,可用summary::marker覆盖 - 内容始终在文档流中,展开后自然推移下方元素,无需手动处理布局
为什么不能直接用 transition: height 实现展开动画
因为 details 展开时高度由内容决定,CSS 的 transition: height 不支持 height: auto —— 浏览器无法计算过渡终点值。
- 尝试写
details { transition: height 0.3s }完全无效 - 可行替代方案只有:
max-height+overflow: hidden(需预估最大高度,如max-height: 500px) - 若要求精确动画、动态高度、或完整手风琴逻辑,建议放弃原生,改用
div+ JS 控制max-height或使用 CSS-in-JS 库 - 原生方案的优势不在动效,而在语义、可访问性、轻量和稳定性
如何让多个 details 实现手风琴效果(点一个、其他收起)
原生 details 默认完全独立,互不影响;要实现互斥,必须加 JS 监听并手动控制 open 状态。
- 所有
details需包裹在同一个父容器里(如<div class="accordion">) <li>监听每个 <code>details的toggle事件(比click更准确,能响应键盘操作) - 用
element.open = true/false而不是removeAttribute('open'),更可靠且触发重排 - 示例逻辑:
document.querySelectorAll('.accordion details').forEach(panel => {
panel.addEventListener('toggle', () => {
if (panel.open) {
document.querySelectorAll('.accordion details').forEach(p => {
if (p !== panel) p.open = false;
});
}
});
});
注意:不要依赖 name 属性来“自动”互斥——那只是某些旧资料的误传,目前(2026 年)无浏览器支持该行为。
容易被忽略的兼容性与无障碍细节
Safari 在 15.4 之前对 details 的 focus 样式和 summary::marker 支持不一致,现在主流浏览器(Chrome/Firefox/Edge/Safari 15.4+)已稳定,但仍需注意:
- 自定义箭头时,别只靠
summary::after,记得用details[open] summary::after区分状态 - 清除默认 marker 后,务必提供视觉反馈(如旋转图标或颜色变化),否则键盘用户无法感知当前状态
- 如果内容含表单控件,确保
details展开后仍可 tab 导航到内部元素(原生支持,但自定义样式可能意外阻断) - 移动端点击区域较小,建议给
summary设置足够 padding,避免误触











