details+summary 是最简可行手风琴方案,现代浏览器原生支持,但 ie 完全不兼容;须确保 summary 为 details 唯一首个子元素且不含块级标签,样式需重置 marker 并用伪元素统一图标,互斥展开和键盘焦点需 js 辅助优化。

details+summary 是最简可行方案
不用 JS、不引框架,现代浏览器原生支持手风琴式问答折叠。Chrome 12+、Firefox 8+、Safari 6.1+ 都能直接跑,Edge 79+ 起稳定支持。IE 完全不认,如果必须兼容 IE,这个方案就该立刻排除。
核心就两条硬规则:summary 必须是 details 的第一个子元素,且只能有一个;summary 里不能塞 div、h3 这类块级标签——哪怕只是想加个换行或 margin,也会让 Safari 或旧 Edge 失去点击响应。
- 正确写法:
<details><summary>Q: 为什么登录失败?</summary><p>可能是密码错误或账号被锁定。</p></details> - 错误写法:
<details><p><summary>Q: ...</summary></p></details>(summary不是首个子元素) - 错误写法:
<details><summary><h3>Q: ...</h3></summary></details>(h3是块级,破坏语义和行为)
清除默认箭头并统一图标状态
各浏览器给 summary 加的右对齐三角形位置、颜色、大小都不一致,直接靠 list-style: none 并不能彻底清掉 Safari 的原生 ::marker。要真正统一外观,得双管齐下。
实操建议:
- 先重置基础样式:
summary { list-style: none; }+summary::marker { content: ""; } - 再用伪元素补图标:
summary::after { content: "▶"; margin-left: 8px; } - 展开时切换:
details[open] summary::after { content: "▼"; } - 别忘了控制间距:
details { margin-block: 0.5em; },否则相邻条目空隙过大
多个问答互斥展开需 JS 辅助
details 原生不支持“单选展开”——也就是点一个,其他自动收起。这是常见需求,但必须自己加 JS 监听 toggle 事件来关掉别的 details。
关键点:
- 监听所有
details的toggle事件,不是click - 检测
event.target.open === true才执行关闭逻辑,避免重复触发 - 用
document.querySelectorAll('details:not([open])')筛选当前未开的,再遍历设open = false - 不要用
querySelectorAll('details').forEach(...)然后无条件设open = false,否则刚点开的那个也会被立刻关掉
示例片段:document.addEventListener('toggle', e => { if (e.target.open) { document.querySelectorAll('details').forEach(d => { if (d !== e.target) d.open = false; }); } });
键盘焦点与无障碍容易被忽略
用户按 Tab 进入 summary、空格键展开,这是原生支持的。但展开后,焦点不会自动跳进内容区——如果答案里有链接、按钮或表单,用户还得手动按多次 Tab 才能到达,体验断层。
修复方式很轻量,但常被跳过:
- 绝对不要给
summary加tabindex或role="button",这会破坏屏幕阅读器识别 - 在
toggle事件中判断details.open === true后,手动focus()到内容区第一个可聚焦元素,比如details.querySelector('a, button, input')?.focus() - 如果内容区首元素是纯文本,可以加一个带
tabindex="-1"的span作为锚点,避免焦点丢失
这个细节不影响功能,但决定了真实用户是否愿意多问几个问题。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











