<details> 中 <summary> 必须是第一个直接子元素,不可嵌套或包裹在其他标签内;支持默认展开(open 布尔属性)、JS 控制(el.open = false)、toggle 事件监听;兼容性需注意 IE 不支持,无障碍需保留原生语义,避免覆盖 role 或隐藏 summary。

details 和 summary 标签怎么写才不塌陷
直接用 <details> 包 <summary>,但浏览器默认样式会让 <summary> 前出现小三角,且点击后展开内容——这没问题;问题常出在内容塌陷、点击无反应或样式错乱。根本原因是:<summary> 必须是 <details> 的第一个子元素,且不能嵌套另一个 <details> 或 <summary>。
- 错误写法:
<details><p><summary>标题</summary></p><p>正文</p></details>(<summary>不是直接子元素) - 正确结构:
<details><summary>标题</summary><p>正文</p></details> - 如果用了 CSS 重置了
outline或list-style,可能让小三角消失,但交互仍存在——建议用appearance: none+ 自定义伪元素控制,而非直接删光
summary 里能放按钮或链接吗
能,但要注意焦点和语义。原生 <summary> 是可聚焦、可键盘操作(Space/Enter)的交互元素,如果在里面塞 <button> 或 <a href>,会导致事件冒泡冲突或双击行为(比如点链接同时触发 details 切换)。
- 避免在
<summary>内写<button onclick="toggle()">——它和父级<details>的默认切换逻辑打架 - 真要放链接,加
event.stopPropagation():例如<summary><a href="#" onclick="event.stopPropagation();doSomething()">跳转</a></summary> - 更稳妥的做法:把链接放在展开后的内容区,而不是 summary 行内
details 默认展开和 JS 控制开关状态
<details open> 可以默认展开,但别以为加个 open="false" 就能关闭——HTML 属性 open 是布尔属性,只看是否存在,不看值。JS 操作要用 open 属性(不是 getAttribute)。
- 默认展开:
<details open><summary>说明</summary><p>内容</p></details> - JS 关闭:
document.querySelector('details').open = false - 监听切换:
el.addEventListener('toggle', () => console.log(el.open))—— 注意只有用户手动触发才会触发toggle事件,JS 赋值不会触发 - 兼容性提示:IE 完全不支持,Safari 12.1+、Chrome 12+、Firefox 49+ 支持良好;如需兼容旧环境,得降级为手写
aria-expanded+ class 切换
无障碍(a11y)容易漏掉的三件事
屏幕阅读器靠 <details> 的隐式 ARIA 角色(role="group")和 <summary> 的 role="button" 来识别,但实际项目中常因以下操作破坏语义:
立即学习“前端免费学习笔记(深入)”;
- 给
<summary>加role="heading"或aria-label:覆盖原生角色,导致“可点击但读不出是开关” - 用
display: none隐藏<summary>:应改用visibility: hidden或clip-path,否则屏幕阅读器完全忽略它 - 展开内容里有
<form>或<input>却没设autofocus:用户展开后焦点不在可操作区域,得手动 Tab 寻找——尤其移动端体验差
细节藏在默认行为里,比如 summary 的键盘响应节奏、focus outline 的视觉反馈、toggle 事件的触发边界——这些不写 JS 也能跑,但一动就露馅。


















