open属性是布尔属性,存在即展开、不存在即收起;写open="false"仍展开,JS应使用toggleAttribute('open')切换状态,监听用toggle事件,CSS用details[open]选择器。

details 元素的 open 属性是布尔属性,不能用字符串值
直接写 open="false" 或 open="0" 不会关闭 <details></details> —— 浏览器只认有没有这个属性,不解析它的值。所以 open 存在即展开,移除即收起。
常见错误是这样写:
<details open="false"><summary>标题</summary>内容</details>
结果它依然展开。正确做法只有两种:open(展开)或不写(默认收起)。
用 JS 切换 open 状态:推荐 toggleAttribute
toggleAttribute 最简洁、语义清晰,且能准确反映 DOM 层面的状态变化(比操作 open 属性值更可靠)。
立即学习“前端免费学习笔记(深入)”;
-
el.toggleAttribute('open'):有就删,没就加 - 避免用
el.open = false—— 它只改 JS 属性,不触发浏览器的折叠动画(部分浏览器下会跳过过渡) - 如果需要强制展开/收起,用
el.setAttribute('open', '')或el.removeAttribute('open')
示例:点击 summary 外区域也能控制开关
实现 Markdown↔ HTML 互转,支持导出 PDF,用于用户请求的文档格式转换。
document.querySelectorAll('details').forEach(d => {
d.addEventListener('click', e => {
if (e.target.tagName !== 'SUMMARY') {
d.toggleAttribute('open');
}
});
});
自动折叠其他已开的 details(手风琴效果)
多个 <details></details> 同时存在时,想实现“只开一个”,关键在于:监听 toggle 事件(它在用户点击 summary 或 JS 触发 toggleAttribute 后触发),然后遍历兄弟节点收起。
-
toggle事件比click更准确:它只在 open 状态实际改变后触发 - 注意不要用
change事件 ——<details></details>不支持 - 用
closest或预设容器 class 来限定作用域,避免误操作全局 details
示例(同一父容器内互斥):
const accordion = document.querySelector('.faq-list');
accordion.addEventListener('toggle', e => {
if (!e.target.hasAttribute('open')) return;
accordion.querySelectorAll('details[open]').forEach(d => {
if (d !== e.target) d.removeAttribute('open');
});
});
折叠动画和排版塌陷问题怎么处理
<details></details> 默认没有 CSS 过渡,直接显示/隐藏会导致内容“闪现”或布局跳动。要平滑,得靠 CSS 配合 max-height 和 overflow 模拟,但要注意:
- 不能直接对
details设transition: max-height—— 因为max-height: 0时内部summary仍可点击,逻辑错乱 - 更稳妥的做法:用
details[open] > *:not(summary)控制子内容的max-height和opacity - 若内容高度不确定,
max-height设为足够大的固定值(如600px),再配合overflow: hidden - 记得给
summary加position: relative或z-index,避免动画过程中被遮挡
真正影响排版的是内容高度突变。JS 层面无法绕过,只能靠 CSS 动画缓冲视觉感受。
细节容易被忽略:toggle 事件不会冒泡到 details 的父元素,但会触发在目标元素自身;如果你用事件委托监听 toggle,必须绑定在 details 自身或 document 上,不能靠父容器捕获。


















