的 open 是布尔属性,仅通过存在与否控制展开状态;js 应用 el.open = true/false 操作,监听 toggle 事件捕获所有状态变更;css 用 details[open] 选择器响应状态,且 必须为首个子元素。

直接写 open 属性就能让 <details></details> 默认展开,不写就收起;它不是字符串,别传 open="true" 或 open="false"——那样反而会强制展开。
open 是布尔属性,不是字符串值
浏览器只检查该属性是否存在,不解析它的值。哪怕你写成 open="false"、open=""、open="anything",只要属性名在标签上,就等效于 open=true。
- ✅ 正确默认展开:
<details open><summary>标题</summary><p>内容</p></details>
- ❌ 错误写法(实际仍展开):
<details open="false">、<code><details open="0"></details> - ⚠️ JS 里读写必须用
el.open(布尔值),不能用el.getAttribute('open')—— 后者返回字符串或null,无法准确反映状态
JS 动态控制 open 状态的坑点
用 JS 切换 open 看似简单,但几个操作容易混淆行为:
- ✅ 推荐:
el.open = true或el.open = false—— 同步更新 DOM 并触发toggle事件 - ❌ 避免:
el.setAttribute('open', 'false')—— 这会让属性存在,实际变成展开 - ❌ 别依赖初始
hasAttribute('open')判断状态:没写open的元素,el.open是false,但el.hasAttribute('open')也是false,二者不能混用 - ⚠️ 设置
el.open = true后再设false,依然会触发两次toggle事件(一次开、一次关)
监听 toggle 事件,而不是 click
toggle 是唯一能可靠捕获所有状态变化的事件,包括用户点击、键盘操作(空格/回车)、以及 JS 修改 open 值。
- ✅ 正确监听:
details.addEventListener('toggle', () => console.log(details.open)) - ❌ 不要给
<summary></summary>绑click—— 会干扰原生焦点、键盘支持和屏幕阅读器行为 - ⚠️
toggle在页面首次加载时不触发,只响应状态变更;且event.preventDefault()对它无效,别白费力气 - ⚠️ 多个
<details></details>共存时,若要做单选折叠(比如 FAQ 只开一个),记得在事件处理中排除自身:if (d !== details) d.open = false
CSS 响应 open 状态要靠 details[open]
样式切换必须用属性选择器 details[open],而不是靠 JS 添加 class——前者是原生、自动、零延迟的。
- ✅ 控制展开后内容显示:
details[open] > *:not(summary) - ✅ 自定义箭头(Chrome/Firefox):
details summary::marker { content: "▶ "; },展开时:details[open] summary::marker { content: "▼ "; } - ⚠️ Safari 15.4 之前不支持
::marker,得退回到summary::before+transform模拟 - ⚠️ 别对
<details></details>设height过渡——它高度由子内容决定,无法动画;如需滑动效果,得用max-height+overflow: hidden,但这已脱离原生逻辑,建议换 JS 方案
最常被忽略的是:summary 必须是 details 的第一个子元素,中间不能有任何空白、注释或其它标签;顺序颠倒、嵌套错位,整个折叠逻辑就静默失效,连报错都没有。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











