原生元素可实现无JS折叠展开,语义清晰、键盘友好、屏幕阅读器自动识别;必须为首个子元素,用CSS伪类切换“展开/收起”文本,避免JS干预以保障SSR和无障碍。

用 details 和 summary 最简实现折叠展开
HTML 原生就支持摘要折叠,不用 JS、不引 CSS,details 元素就是为此设计的。浏览器兼容性已覆盖 Chrome 12+、Firefox 49+、Safari 6+、Edge 79+,移动端也完全可用。
常见错误是手动写 div + JS 控制显隐,既增加代码量又易出可访问性问题。原生方案语义清晰、键盘可操作(空格/回车触发)、屏幕阅读器自动识别展开状态。
-
summary必须是details的第一个子元素,否则不生效 - 默认收起,加
open属性可默认展开:<details open></details> - 不要给
summary套button—— 它本身已是可点击控件,嵌套会破坏语义和焦点逻辑 - 内联样式或 CSS 选择器可定制外观,例如:
summary::marker { content: "▸ "; }替换默认三角符号
让摘要文字在收起时显示“展开”、展开后显示“收起”
原生 summary 不自动切换文字,但可以用 CSS 的 :not([open]) 和 [open] 伪类分别控制两段文本的显隐,无需 JS。
关键点在于把两种状态的文字都写进 summary,靠 CSS 切换显示:
立即学习“前端免费学习笔记(深入)”;
生成可在 deepbi 沙箱 iframe 内运行或作为独立文件运行的交互式 HTML 页面,使用 `window.deepbi` JS SDK 实现数据查询、空间管理、文件浏览及用户操作。当用户提出以下需求时启用该能力: - 创建 KPI 仪表盘、数据表格、文件浏览器、成员列表、管理页面; - 明确要求“转成 dhtml”、“转译成 HTML”、“把 XX 页面转成……”、“控制台页面”、“管理后台”、“DeepBI 页面迁移”; - 提及位于 `apps/console/src/featur
<details>
<summary>
<span class="summary-closed">展开摘要</span>
<span class="summary-open">收起摘要</span>
</summary>
<p>这里是正文摘要内容……</p>
</details>
CSS 部分:
.summary-closed { display: inline; }
.summary-open { display: none; }
details[open] .summary-closed { display: none; }
details[open] .summary-open { display: inline; }
- 不能只靠 JS 切换文本——那样对禁用 JS 的用户或 SSR 渲染不友好
- 避免用
visibility: hidden,它仍占布局空间;用display: none更干净 - 如果摘要内容含图片或 iframe,收起时它们仍会加载(这是浏览器行为),敏感场景需额外处理
折叠区域高度突变导致页面跳动怎么办
当摘要内容较长,details 展开瞬间高度剧增,可能造成下方元素突然下移,影响阅读体验。这不是 bug,而是流式布局的自然表现,但可以缓解。
- 给
details设置最小高度(如min-height: 2em),预留基础空间 - 用 CSS 过渡仅作用于
max-height(配合固定值)可模拟展开动画,但需预估最大高度,不适用于动态长度内容 - 更稳妥的做法是:收起时用
overflow: hidden+height: 0+padding: 0组合,并过渡这三项 —— 但会丢失原生可访问性,慎用 - 真正需要平滑动画且兼顾语义?那就得退回到 JS 方案,用
aria-expanded+max-height过渡,并手动管理焦点
服务端渲染(SSR)或静态站点中如何保持初始状态一致
若用框架(如 Next.js、Nuxt)或静态生成器(Hugo、Jekyll),details[open] 属性必须在 HTML 输出时就存在,否则客户端首次渲染会闪动(先收起再 JS 补开)。
- 不要依赖
useEffect或mounted钩子去加open—— SSR 无法执行,状态不一致 - 在模板层根据数据字段直接输出属性,例如 Jekyll:
<details if page.expanded endif></details> - 若状态来自用户偏好(如 localStorage),首次加载仍会闪动,建议收起为默认,用
prefers-reduced-motion媒体查询降级动画
原生 details 看似简单,但细节全在属性时机、CSS 作用域和可访问性链路上。最容易被忽略的是:它不支持嵌套 details 的状态联动,也不广播事件,需要跨区域响应时就得自己补逻辑。


















