details 标签配合 summary 可零 JavaScript 实现语义化展开折叠,天然支持可访问性与键盘操作;自定义箭头需用 list-style: none 清除原生图标,再通过 ::marker 或 ::before 重绘;程序化控制仅需操作 open 属性并监听 toggle 事件。

用 details 和 summary 最快实现展开折叠
不用写一行 JavaScript 就能完成,details 是原生语义化标签,浏览器默认支持点击 summary 切换展开状态。它天然可访问、支持键盘(空格/回车触发)、无需额外 ARIA 属性。
常见错误是手动模拟这个行为:比如用 div + click + classList.toggle,结果漏掉焦点管理、键盘响应或屏幕阅读器提示。
示例用法:
<details> <summary>点击展开说明</summary> <p>这里是折叠的内容,可以放任意 HTML。</p> </details>
-
details默认收起,加open属性可默认展开:<details open> -
summary必须是details的第一个子元素,否则不生效 - 不要给
summary套button—— 它本身已是可交互元素,嵌套会破坏语义和键盘行为
需要自定义样式时怎么覆盖默认箭头
所有现代浏览器对 summary 都显示一个小三角(方向随展开状态变化),但这个箭头无法用普通 CSS 选中。必须用伪元素配合 list-style 清除再重绘。
立即学习“前端免费学习笔记(深入)”;
关键点在于:先禁用原生标记,再用 ::marker 或 ::before 补上自定义图标。
- 清除默认箭头:
summary { list-style: none; } - 添加自定义图标(推荐用
::marker,更语义):summary::marker { content: "▶"; },展开后改为"▼"(需配合details[open] summary::marker) - 若要兼容旧版 Safari(
::marker支持较晚),可用summary::before+transform: rotate()动画控制旋转 - 注意:Chrome/Firefox 对
summary::marker的垂直对齐支持不一致,建议加vertical-align: middle统一基线
JavaScript 控制展开状态的正确写法
只有当需要程序化控制(如页面加载后根据条件展开、联动多个 details、或封装成组件)时才用 JS。直接操作 open 属性即可,不要操作 display 或 height。
- 展开:
document.querySelector('details').open = true - 收起:
document.querySelector('details').open = false - 监听变化:用
toggle事件,不是click—— 用户可能用键盘打开,toggle覆盖所有触发方式:el.addEventListener('toggle', () => { ... }) - 避免在
toggle里调用el.open = true/false,会造成无限循环
为什么不用 max-height + transition 动画
这种纯 CSS 方案看似灵活,但实际坑多:高度不确定时得设极大值(如 max-height: 500px),内容超长就截断;设为 0 → none 又无法过渡;JS 测高再设值又失去声明式优势。
除非明确要求「内容区域有高度动画」且能接受测高逻辑,否则没必要绕开 details。它的展开是即时的,但用户感知不到突兀——因为内容区域本来就没有预设高度约束,布局自然流式展开。
真正需要动画的场景极少,多数产品设计规范已接受原生无动画行为;强行加动画反而增加维护成本和可访问性风险(比如动画未关闭时对前庭敏感用户不友好)。



















