details默认展开只需写open属性不带值;open属性存在即展开,与值无关;JS应操作open布尔属性而非setAttribute;CSS用details[open]选择器;监听toggle事件获取状态变化。

open 属性存在即展开,不写就收起;写 open="false" 反而强制展开——这是最常翻车的地方。
HTML 中 details 默认展开的唯一写法
只写 open,不带等号、不带引号、不带任何值:
<details open> <summary>配置详情</summary> <p>这里是默认可见的内容</p> </details>
-
<details open>→ 正确,默认展开 -
<details open="true">、<details open="false">、<details open="">→ 全部等效于展开(因为属性“存在”) -
<details>→ 默认收起(最安全的初始状态) - 服务端渲染或静态 HTML 场景下,这是最稳定、无 JS 依赖的方式
JavaScript 动态控制 open 状态的正确姿势
必须操作 DOM 元素的 open 属性(布尔值),而不是 HTML 属性:
- ✅ 正确:
el.open = true、el.open = false、console.log(el.open) - ❌ 错误:
el.setAttribute('open', 'false')→ 属性被写入,“存在即展开”,结果与预期相反 - ⚠️ 注意:
el.hasAttribute('open')和el.open不等价:初始没写open时两者都为false;但执行el.open = true后,hasAttribute仍返回false(HTML 源码未变) - 推荐切换方式:
el.toggleAttribute('open'),语义清晰,且同步 DOM 与 HTML 属性
CSS 响应展开/收起状态只能用 details[open]
不能靠 class、不能用 [open="false"],浏览器根本不解析 open 的值:
立即学习“前端免费学习笔记(深入)”;
- ✅ 正确:
details[open] .content { max-height: 200px; } - ✅ 正确:
details:not([open]) summary::after { content: "▼"; } - ❌ 错误:
details[open="false"]→ 无效选择器 - ❌ 错误:
details.open→open不是 class,不存在这个类名 - 真正容易被忽略的是:JS 修改
el.open后,CSSdetails[open]能实时响应,但hasAttribute('open')依然拿不到更新 —— 脚本和样式对“状态”的感知路径完全不同
监听展开/收起变化只能用 toggle 事件
details 没有 change 事件,click 也不可靠:
- ✅ 正确:
el.addEventListener('toggle', () => console.log(el.open)),事件在状态变更后派发,此时el.open已是最新的布尔值 - ❌ 错误:
el.addEventListener('change', ...)→ 根本不会触发 - ❌ 错误:给
<summary>绑click→ 干扰键盘(Enter/Space)和屏幕阅读器行为 - 首次加载不触发
toggle,仅在用户交互或 JS 主动修改el.open后才触发



















