<details> 是专为可折叠卡片设计的原生 HTML 元素,语义正确、键盘可用、屏幕阅读器友好,默认折叠,点击 <summary> 展开,浏览器自动管理状态、焦点和 ARIA 属性。

用 <details> 和 <summary> 实现原生可折叠卡片
不用 JS、不写动画,也能做出语义正确、键盘可用、屏幕阅读器友好的收起按钮——<details> 就是专干这事的。它默认折叠,点击 <summary> 展开,浏览器自动管理 open 状态、空格/回车触发、焦点流转和 ARIA 暴露。
常见错误是用 <div> + onclick + display: none 手动模拟,结果要自己补 aria-expanded、监听键盘、防止 focus 丢失,反而引入兼容性 bug。
-
<summary>必须是<details>的第一个子元素,否则老版 Safari 会降级为普通块容器 - 不要给
<summary>绑onclick或调preventDefault(),会破坏原生行为 - 需要默认展开?直接加
open属性:<details open><summary>标题</summary><p>内容</p></details> - 箭头图标由浏览器渲染,CSS 可覆盖:
summary::marker { content: "▶ "; },但别删掉,否则影响无障碍
想加平滑展开动画?必须绕开 height: auto 陷阱
<details> 自带展开逻辑,但 CSS 动画没法直接对 height: auto 做过渡——浏览器不知道“auto”具体是多少像素,动画会卡顿或失效。
解决方法不是硬写 JS 测高,而是用现代 CSS 技巧绕过高度计算:
立即学习“前端免费学习笔记(深入)”;
- 用
max-height+overflow: hidden模拟:设一个足够大的值(如max-height: 500px),配合transition: max-height 0.3s ease - 更稳妥的是用
clip-path或transform: scaleY(),它们能直接作用于auto高度内容,且性能更好 - 如果内容含图片或字体加载延迟,动画可能提前结束——得监听
img.onload或用ResizeObserver补触发重绘
多个卡片共用一个“全部展开/收起”按钮时,别用 class 切换状态
批量控制时,常见做法是给所有卡片加 class="collapsed",再用 JS 切换这个类。问题在于:状态和 DOM 绑死,刷新后丢失;且无法与原生 <details> 的 open 属性同步,导致 aria 不一致。
正确做法是直接操作 open 属性本身:
- 获取全部
<details>元素:document.querySelectorAll('details') - “全部展开”:遍历并设
el.open = true;“全部收起”:设el.open = false - 注意:设
open = false会触发toggle事件,但不会重复触发(和 click 不同),可安全使用 - 避免用
el.setAttribute('open', ''),因为移除属性要用removeAttribute('open'),不如直接赋值布尔值干净
移动端点击区域太小?别只靠 padding 加大触控面积
<summary> 默认是行内元素,padding 在某些安卓浏览器里可能不生效,或者被截断。单纯加大 padding 还可能撑开布局,尤其在 flex 容器中。
可靠方案是提升整个交互区域的命中率:
- 把
<summary>设为display: block,再加padding和min-height - 用
margin推开相邻内容,避免误触(比如卡片之间留 8px 以上间隙) - 关键:给
<summary>加cursor: pointer,让用户明确知道这是可点区域 - 如果卡片嵌套在
<article>或<section>里,确保父容器没设pointer-events: none之类干扰
最易被忽略的一点:展开后内容若含表单控件(如 <input>),务必检查 tabindex 顺序是否连贯——原生 <details> 会自动把焦点移到第一个可聚焦子元素,但自定义动画可能打断这个链路。



















