<details>和<summary>是轻量、原生、无障碍友好的可折叠方案,支持键盘操作、焦点管理与ARIA角色,open属性为存在即真型布尔属性,需用伪元素定制样式且动态插入后需手动设置open状态。

<details> 和 <summary> 是目前最轻量、原生支持可折叠内容的方案,不需要 JS 就能实现交互,且语义清晰、无障碍友好。
为什么不用 display: none 手动控制显隐?
手动切换 display 或 visibility 确实能隐藏内容,但会丢失以下关键能力:
- 无法被屏幕阅读器识别为“可展开区域”,影响可访问性
- 没有默认焦点管理(比如按
Enter或Space键触发展开) - 缺少原生状态同步(
open属性自动反映当前是否展开) - 需额外写 JS 绑定事件、维护状态、处理过渡动画
而 <details> 天然支持键盘操作、焦点流转和 ARIA 隐式角色(role="group" + aria-expanded),浏览器已内置逻辑。
open 属性不是布尔值,别直接写 open="false"
open 是一个**存在即为真**的布尔属性。它的行为只取决于是否出现在标签中,跟值无关:
立即学习“前端免费学习笔记(深入)”;
<details open><summary>默认展开</summary><p>内容</p></details> <details><summary>默认收起</summary><p>内容</p></details> <details open="false"><summary>这依然会默认展开</summary></details>
想初始收起,就不要写 open;想初始展开,只写 open(不带等号或值)。JS 控制时也应使用 element.open = true/false,而非设置属性字符串。
样式定制必须用 <summary> 伪元素,不能靠 class
<summary> 默认带一个原生三角指示符(↓/→),但这个图标无法通过常规 CSS 选择器覆盖。要自定义箭头或移除它,必须用:
details summary {
list-style: none; /* 移除默认三角 */
}
details summary::marker {
content: "▶ "; /* 替换为自定义符号 */
}
details[open] summary::marker {
content: "▼ ";
}注意:::marker 在部分旧版 Safari 中支持不佳,如需兼容,可改用 background-image 或绝对定位图标。另外,<summary> 不能设 display: flex 后再用 align-items 垂直居中——它内部有匿名 box,容易错位,稳妥做法是用 line-height 或 padding 调整。
真正麻烦的不是写法,而是很多人在 JS 动态插入 <details> 后忘了调用 element.setAttribute('open', '') 或赋值 .open = true —— DOM 插入后不会自动触发浏览器对布尔属性的解析,这点容易漏掉。



















