是html5原生折叠容器,需搭配唯一子元素使用,默认支持键盘交互与可访问性;错误嵌套会引发渲染异常;自定义样式应避免破坏语义和焦点逻辑;js控制需用布尔赋值或toggleattribute();兼容性差时应降级为静态内容。

details 标签的基本用法和默认行为
<details></details> 是 HTML5 原生支持的折叠/展开容器,无需 JS 就能实现基础交互。<summary></summary> 是其唯一允许的直接子元素,作为触发按钮——点击它会切换 <details></details> 的 open 属性状态。
浏览器默认给 <summary></summary> 加了小三角图标(方向随开闭自动翻转),且自带 focus 样式和键盘支持(空格/回车可触发),这点比手写 <div> + JS 更健壮。
<p>常见错误:把其他元素(比如 <code><p></p> 或多个 <summary></summary>)直接塞进 <details></details> —— 这会导致部分浏览器忽略后续内容或渲染异常。
- 必须只放一个
<summary></summary>作为首子元素 - 其余内容(
<p></p>、<ul></ul>、<table> 等)放在 <code><summary></summary>后面即可 - 想默认展开?加
open属性:<details open></details>
自定义 summary 样式但保留原生交互逻辑
直接对 <summary></summary> 写 CSS 很容易破坏默认图标或焦点表现。关键是:不要用 appearance: none 或 list-style: none 粗暴清除,而应针对性覆盖。
立即学习“前端免费学习笔记(深入)”;
summary {
list-style: none;
}
summary::marker {
content: "▶ ";
}
details[open] > summary::marker {
content: "▼ ";
}
这样既控制了图标,又没干扰语义和键盘操作。若用 display: flex 或绝对定位调整布局,务必测试 Tab 键能否聚焦到 <summary></summary> 上——否则屏幕阅读器用户会丢失交互入口。
- 避免给
<summary></summary>设pointer-events: none,否则点击失效 - 不要用
summary { display: block; }覆盖默认display: list-item,可能影响 marker 渲染 - 如需禁用某处折叠功能,改用
disabled不生效,应移除<summary></summary>或用 JS 阻止默认行为
JS 控制 open 状态与事件监听
通过 JS 操作 open 属性或 toggle() 方法可动态控制,同时监听 toggle 事件响应用户操作。
注意:该事件在用户点击或按键触发后才派发,不是每次属性变更都触发;且不冒泡,不能委托到父级。
const details = document.querySelector('details');
details.addEventListener('toggle', () => {
console.log('当前是否展开:', details.open);
});
// 展开
details.open = true;
// 或
details.toggleAttribute('open');
容易踩的坑是误以为 open 是布尔属性就用 details.setAttribute('open', 'true')——这无效,必须赋值为布尔类型或调用 toggleAttribute。
- 设置
details.open = false会收起,但不会触发toggle事件(只有用户交互才触发) - 服务端渲染时若初始设
open,客户端 JS 修改前会先闪现展开态,敏感场景建议用 CSS 隐藏未初始化状态 - 多个
<details></details>共存时,别用document.querySelectorAll('details').forEach(...)绑定事件却忘了清理,容易内存泄漏
兼容性与渐进增强处理
现代浏览器(Chrome 12+、Firefox 49+、Safari 6.1+、Edge 79+)均支持,但 IE 完全不支持,旧 Android WebView(≤4.4)也有问题。
如果必须兼容老环境,不要用 JS 完全模拟 <details></details> 行为(成本高、可访问性难保障),而是降级为静态内容——即服务端判断 UA,不支持时直接不加 <details></details> 和 <summary></summary>,让所有内容平铺显示。
CSS 方面,可用 @supports (display: list-item) 区分支持情况,但更稳妥的是检测 HTMLDetailsElement 构造函数是否存在:
if ('open' in HTMLDetailsElement.prototype) {
// 支持 details,可加额外 JS 增强
} else {
// 降级:插入按钮 + 手动切换 class 控制 display
}
真正麻烦的不是样式或 JS,而是当内容含表单控件(如 <input>)时,折叠状态下它们仍存在于 DOM 中,且可能被屏幕阅读器读出——需配合 aria-hidden 和 tabindex 动态管理焦点流,这点常被忽略。










