details 和 summary 的可折叠功能依赖严格 HTML 结构:summary 必须是 details 的直接且首个子元素,否则点击失效、语义丢失;open 为布尔属性,不可赋值;自定义箭头应通过 summary::before 实现,禁用 ::marker;嵌套建议不超过两层,表单内需防提交干扰;IE 需 polyfill。

details 和 summary 是原生可折叠组件,不用 JS 就能工作,但结构错一点就点不动、样式乱、Safari 默认展开关不掉——问题几乎全出在 HTML 结构或 CSS 干预上。
details 必须严格包裹 summary 且 summary 是第一个子元素
浏览器只认 summary 作为触发器,而且它必须是 details 的**直接子元素**,且排第一。中间插个 <div>、前面加个空格、或者把 summary 放在内容后面,都会让折叠失效或语义丢失。
- ✅ 正确写法:
<details><summary>标题</summary><p>内容</p></details>
- ❌ 错误写法:
<details><div><summary>标题</summary></div><p>内容</p></details>
(summary不是直接子元素) - ❌ 错误写法:
<details><p>内容</p><summary>标题</summary></details>
(summary不是首个子元素)
用 open 属性控制默认展开状态
open 是布尔属性,有即展开,无即收起。它可被 JS 动态读写,也能被用户点击切换。注意:它不是字符串值,别写成 open="true" 或 open="open"。
- 默认展开:
<details open><summary>常见问题</summary><p>答案在这里</p></details>
- JS 控制展开:
el.open = true或el.toggleAttribute('open') - Safari 有个老毛病:如果页面加载时 DOM 已含
open,但 JS 稍后又设el.open = false,可能视觉上没变化——得加一次重绘,比如el.offsetHeight触发回流后再设
自定义箭头要用 ::before,别碰 ::marker
summary::marker 在 Safari 和旧版 Chrome 中支持不稳定,甚至完全不渲染。更可靠的方式是隐藏原生指示符,用 ::before 插入自定义图标。
立即学习“前端免费学习笔记(深入)”;
- 先清空原生箭头:
summary::marker { content: "" } - 再加图标:
summary::before { content: "▶"; margin-right: 4px; } - 展开时换图标:
details[open] > summary::before { content: "▼" } - 千万别用
display: none隐藏summary::marker,某些浏览器会连带禁用点击区域
嵌套 details 或放在表单里容易出兼容性问题
嵌套 details 在大多数现代浏览器中可行,但 Safari 对嵌套层级超过 2 层的 toggle 事件监听不一致;放在 <form> 内时,部分浏览器会把 summary 当成可提交控件(尽管规范不允许),导致意外行为。
- 嵌套建议最多两层,第三层起改用 JS 模拟折叠逻辑
- 表单内使用时,给
summary加tabindex="-1"并监听click手动切open,避免焦点/提交干扰 - IE 完全不支持,如需兼容,必须引入 polyfill(如 details-polyfill),但注意它不修复无障碍问题
最常被忽略的是:即使你没写一行 CSS 或 JS,只要结构不对或用了不兼容的伪元素,details 就会静默失效——它不像 div 那样“容错”,而是严格按规范执行。调试时优先检查 DOM 树顺序和属性拼写,而不是急着加脚本。



















