原生支持折叠展开,语义正确且无障碍友好;必须为首个子元素,漏写或错位将失效;默认收起,加open属性可默认展开;支持嵌套与任意html内容;ie不支持但现代浏览器全覆盖;样式需用list-style:none+::after模拟箭头并监听[open]做旋转动画;禁用height/overflow以免破坏过渡;避免内嵌或,表单控件需保持tab可达。

用 <details></details> 和 <summary></summary> 实现折叠面板,不用 JS
HTML 原生就支持折叠展开,不需要写一行 JavaScript。<details></details> 是容器标签,<summary></summary> 是点击区域,浏览器自动处理展开/收起状态和箭头图标。这是最轻量、语义正确、无障碍友好的方案。
常见错误是把 <summary></summary> 放在 <details></details> 外面,或漏掉 <summary></summary> —— 这会导致内容始终可见,且无法触发折叠。
-
<details></details>默认收起,加open属性可默认展开:<details open></details> -
<summary></summary>必须是<details></details>的第一个子元素,否则无效 - 里面可以放任意 HTML 内容(
<p></p>、<ul></ul>、甚至嵌套另一个<details></details>) - 不支持 IE,但 Chrome/Firefox/Safari/Edge 全部原生支持(2026 年已无兼容顾虑)
<details></details> 的样式控制:怎么改箭头、颜色、动画
浏览器默认给 <summary></summary> 加了小三角,但不能直接用 CSS 伪元素覆盖它;要隐藏原生箭头,得用 list-style: none + 自定义 ::marker 或背景图。
关键点:Chrome 和 Firefox 对 ::marker 支持不一致,稳妥做法是用 display: flex + ::after 模拟箭头,并监听 [open] 属性做旋转动画。
- 移除默认箭头:
summary { list-style: none; } - 添加自定义图标:
summary::after { content: "▶"; transition: transform 0.2s; } - 展开时旋转:
details[open] summary::after { transform: rotate(90deg); } - 注意:不要对
<details></details>设置height或overflow,会破坏原生过渡动画
替代方案:为什么别用 <div> + JS 手动实现
<p>新手常想“自己用 <code><div> 控制 <code>display: none/block”,这看似灵活,实则埋坑:
- 失去语义:屏幕阅读器无法识别这是可交互的折叠区域,无障碍失败
- 状态同步难:JS 需手动管理 open/close 状态、焦点、键盘操作(Enter/Space 键响应)
- SEO 不友好:搜索引擎可能忽略 JS 动态显示的内容
- 多实例易出错:每个面板都要单独绑定事件、维护状态变量,代码冗余
- 移动端手势支持弱:原生
<details></details> 自带触摸优化,手写 JS 很难做到同等体验
实际使用时容易被忽略的细节
<details></details> 自带触摸优化,手写 JS 很难做到同等体验折叠面板不是“写了就能用好”的功能,几个真实项目里反复踩过的点:
-
<summary></summary>里别放<button></button>或<a></a>—— 会触发双重点击行为,且破坏语义 - 如果内容含表单控件(如
<input>),确保它们在收起状态下仍可被 tab 键访问(<details></details>默认保持 tabindex 可达) - 服务端渲染时,避免在
<details></details>内部做条件渲染逻辑,否则客户端 hydration 可能错乱 - 不要用
!important强行覆盖summary::marker,Firefox 目前不支持该伪元素样式化











