原生 details 元素最省事,语义正确且自带可访问性;需自定义动画时用 max-height 过渡,js 仅通过 class 控制状态,注意移动端点击穿透与滚动问题。

点击卡片触发展开,用 details 最省事
原生 details 元素就是干这个的,不用写 JS、不依赖框架,语义正确,还自带可访问性(键盘 Enter / Space 可切换)。适合纯静态内容或简单详情展示。
常见错误是手动监听 click 再切 display 或 height,结果破坏了语义、丢掉屏幕阅读器支持、动画卡顿、还得自己管焦点。
-
summary标签必须作为details的第一个子元素,它就是那个可点的标题栏 - 展开/收起状态由浏览器自动维护,可通过
details[open]伪类做样式区分 - 默认箭头样式各浏览器不同,可用
summary::marker覆盖,但 Safari 目前不支持该伪元素
<details><summary>? 订单 #12345</summary><p>下单时间:2024-06-15 14:22</p> <p>商品:无线耳机 × 1,充电宝 × 2</p> </details>
需要自定义动画?用 max-height + transition
如果必须有平滑高度展开(比如从 0 到具体内容高度),details 不支持 CSS 动画,得换方案。核心思路是:用 max-height 替代 height,避免无法过渡的问题。
将调研报告、方案对比、数据分析、需求梳理、会议纪要、设计说明、代码评审、学习笔记等任务产物输出为可在浏览器直接打开的单文件 HTML,替代 Markdown 作为最终交付物。Markdown 在信息密度、视觉清晰度和可分享性上已跟不上 AI 产物的丰富度,HTML 能同时承载排版、表格、SVG 等。
关键点不是“怎么动”,而是“怎么设安全的 max-height 值”。设太小会截断,设太大动画慢且不精准。
- 不要用
height: auto过渡——CSS 不支持auto做 transition - 把展开内容包在独立容器里(如
<div class="card-body">),只对它做 <code>max-height控制 - 初始
max-height: 0,展开时设为一个“足够大但不过分”的值,比如500px;收起再切回0 - 加
overflow: hidden防止内容溢出
.card-body {
max-height: 0;
overflow: hidden;
transition: max-height 0.3s ease-out;
}
.card.open .card-body {
max-height: 500px;
}
JavaScript 控制展开逻辑,别直接操作 style
手动写 JS 切换展开状态时,最常踩的坑是直接改 element.style.height 或 element.style.display,这会污染内联样式、难维护、和 CSS 类冲突。
应该用 class 控制状态,让样式层统一管理表现,JS 只负责逻辑判断和 class 切换。
- 给卡片容器加基础类(如
card),展开态加card--expanded - 用
element.classList.toggle('card--expanded')切换,比setAttribute更安全 - 如果需异步加载详情(比如点开才请求 API),在
fetch成功后再加 class,避免空内容闪一下 - 注意:点击区域如果是
summary或自定义按钮,确保event.preventDefault()仅在必要时调用(比如按钮本身是<a href="#"></a>)
移动端点击穿透和滚动问题很常见
卡片在 iOS Safari 或某些安卓 WebView 中,点一下没反应、或者点开后页面意外滚动,通常不是代码逻辑错,而是交互细节没处理好。
- 给卡片容器加
cursor: pointer和-webkit-tap-highlight-color: transparent,消除点击高亮延迟 - 展开内容若含表单控件(如
input),iOS 会自动滚动到输入框位置,可在展开后用el.scrollIntoView({ block: 'nearest' })微调 - 避免在
details外层再套一层onclick,否则可能触发两次事件(summary自带 click,外层又监听一次) - 真机测试时,优先用
touchstart替代click做响应(尤其低版本安卓),但注意details本身已兼容 touch
复杂点在于:动画精度、可访问性、移动端行为三者很难同时完美兼顾。多数场景下,优先保语义和可访问性,动画次之;非要定制动画,就接受 max-height 的取整妥协。










