open是布尔属性,仅检测存在与否;正确写法为<details open>或<details>,JS应直接操作el.open而非setAttribute,CSS用details[open]选择器,事件监听用toggle。

open属性是布尔属性,不是字符串开关
写 open="false" 会强制展开,不是收起——这是最常翻车的地方。浏览器只检测属性是否存在,不解析等号右边的值。open、open=""、open="banana" 全部等效于展开;只有完全不写 open 才默认收起。
正确写法只有两种:
-
<details open><summary>标题</summary><p>内容</p></details>→ 默认展开 -
<details><summary>标题</summary><p>内容</p></details>→ 默认收起
JavaScript 动态控制必须读写 open 属性,别碰 setAttribute
el.open 是 DOM 反射属性,直接赋布尔值即可同步状态;el.setAttribute('open', 'false') 会把属性写入 HTML,导致“存在即展开”,实际反而展开。
- ✅ 正确:
el.open = true、el.open = false、console.log(el.open) - ❌ 错误:
el.setAttribute('open', 'false')、el.getAttribute('open') - ⚠️ 注意:
el.hasAttribute('open')查的是 HTML 源码,el.open查的是当前 DOM 状态,二者不同步
CSS 响应展开状态只能用 details[open],不能用伪类或错误选择器
:open 是伪类,但仅适用于 <details> 元素本身(Chrome 120+ 支持,Safari 仍不稳定),而 details[open] 是兼容性更好、更可靠的属性选择器,所有现代浏览器都支持。
立即学习“前端免费学习笔记(深入)”;
- ✅ 推荐:
details[open] .content { max-height: 300px; } - ✅ 图标切换:
details summary::after { content: "▼"; } details[open] summary::after { content: "▲"; } - ❌ 无效:
details[open="false"]、summary:open(summary没有:open伪类)
监听状态变化必须用 toggle 事件,不是 click 或 change
details 没有 change 事件;给 summary 绑 click 会漏掉键盘操作(Enter/Space),且干扰屏幕阅读器行为。只有 toggle 是规范定义的、唯一可靠的事件。
- ✅ 正确:
el.addEventListener('toggle', () => console.log(el.open))—— 触发时el.open已是最新的布尔值 - ❌ 错误:
el.addEventListener('change', ...)→ 根本不会触发 - ⚠️ 注意:JS 直接赋值
el.open = true不会触发toggle,它只响应用户交互
details[open] 会响应 JS 设置的 el.open = true,但 el.hasAttribute('open') 依然返回 false——这两条路径完全独立,混用就出错。



















