details 元素配合 summary 可原生实现手风琴效果,无需 JS 和 CSS 框架;details 必须直接包含 summary 为第一子元素,支持键盘操作与屏幕阅读器,默认独立开关,加 open 属性可默认展开。

用 details 和 summary 最快实现原生手风琴
不用 JS、不引 CSS 框架,HTML5 原生就支持手风琴交互。核心是 details 元素——它默认可折叠,且自带语义和键盘可访问性(空格/回车展开,Esc 收起)。
常见错误是手动写 div + JS 控制 display,结果丢失焦点管理、屏幕阅读器支持,还多写十几行代码。
实操建议:
-
details必须直接包含一个summary作为第一子元素,否则无法触发折叠逻辑 - 多个
details并列时,默认各自独立开关,无需额外处理 - 想默认展开?加
open属性: - 注意:Safari 旧版本(summary::marker 样式支持有限,如需自定义箭头,优先用伪元素覆盖而非删 marker
用 CSS 覆盖默认样式,避免布局塌陷
details 默认有上下外边距、summary 有粗体和 marker(小三角),直接用会和现有设计冲突。关键不是“重置所有”,而是防塌陷和保持可点击区域。
容易踩的坑:
-
summary默认是display: list-item,设display: block后 marker 消失,但必须补上list-style: none防止兼容性问题 - 收起时
details高度为 0,但内容仍占文档流,需用details[open] > *:not(summary)控制子内容显隐,而不是依赖 height 过渡(原生不支持 height 动画) - 若内容含表单或 iframe,收起后仍可能被聚焦,建议加
tabindex="-1"到非open状态下的子元素
简单示例(带基础过渡):
details {
margin: 0;
}
summary {
display: block;
padding: 8px 12px;
background: #f5f5f5;
cursor: pointer;
}
summary::marker {
content: "▶";
}
details[open] summary::marker {
content: "▼";
}
details > *:not(summary) {
padding: 0 12px;
animation: fadeSlide 0.2s ease-out;
}
@keyframes fadeSlide {
from { opacity: 0; transform: translateY(-6px); }
to { opacity: 1; transform: translateY(0); }
}
需要多选 or 单选?靠 JS 补足逻辑缺口
原生 details 天然支持多选(多个同时展开),但产品常要求“单选手风琴”(展开一个,其他自动收起)。这不是 HTML 能解决的,得用 JS 监听并控制。
关键点:
- 监听所有
summary的click,而非details的toggle事件(后者在 Safari 中不可靠) - 用
event.currentTarget.closest("details")定位当前项,再用querySelectorAll("details")找到其他项,逐个设open = false - 避免重复绑定:检查是否已存在
data-accordion-handled属性再初始化 - 如果页面动态插入新
details,得重新绑定,或用事件委托(但注意summary不冒泡 click 到details)
移动端点击区域太小?别只加 padding
触摸设备上,summary 默认点击区只有文字高度,用户容易点不中。光加 padding 可能撑开整个容器,破坏布局。
更稳妥的做法:
- 保持
summary内联尺寸不变,用::before或::after生成一个透明的、足够大的绝对定位层覆盖点击区 - 或者给
summary设min-height: 44px(iOS 推荐最小触控尺寸),配合display: flex+align-items: center垂直居中文本 - 禁用
user-select: none,否则长按可能触发复制菜单,干扰折叠操作
复杂点在于:动画、可访问性、响应式点击区这三者要同时满足,而很多人只调样式,忘了测试 VoiceOver 或 TalkBack 下的焦点路径。真正上线前,至少用 Safari 的“辅助功能检查器”扫一遍。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











