在前端开发中,折叠与展开(Accordion)是一种极其常见的交互模式,广泛出现在 FAQ 页面、侧边栏导航、移动端菜单等场景中。过去,我们通常依赖 JavaScript 甚至第三方库来实现这一效果。然而,HTML5 早已为我们提供了一个原生解决方案:<details> 元素。
它不仅语义清晰、开箱即用,还天然支持无障碍访问。配合 CSS 的样式定制能力,几乎可以覆盖大多数折叠交互需求。本文将带你从入门到精通,彻底掌握 <details> 的使用与进阶技巧。
一、基础认知
1.1 元素组成
<details> 元素由两部分组成:
元素 | 角色 | 说明 |
|---|---|---|
<summary> | 标题区 | 始终可见,点击后触发展开或收起 |
其余子元素 | 内容区 | 折叠状态下隐藏,展开后显示 |
<details>
<summary>什么是 Flexbox?</summary>
<p>Flexbox 是 CSS3 中的一种一维布局模型,用于在容器内对子元素进行排列、对齐和分配空间。</p>
</details>如果省略 <summary>,浏览器会自动生成一个默认文本(通常为 "Details" 或 "详细信息")。
1.2 open 属性
open 是 <details> 唯一的布尔属性,用于控制初始状态:
<!-- 默认收起 -->
<details>
<summary>收起状态</summary>
<p>需要点击才能看到。</p>
</details><!-- 默认展开 -->
<details open>
<summary>展开状态</summary>
<p>页面加载后直接可见。</p>
</details>1.3 底层原理
浏览器对 <details> 的默认渲染行为如下:
/* 浏览器 UA 样式表中的默认规则 */
details > *:not(summary) {
display: none; /* 内容默认隐藏 */
}
details[open] > *:not(summary) {
display: block; /* 展开时显示 */
}
summary {
display: list-item; /* 作为列表项渲染 */
list-style: disclosure-closed; /* 显示三角箭头 */
}
details[open] > summary {
list-style: disclosure-open; /* 展开时箭头方向改变 */
}由此可见,折叠与展开的核心机制是 CSS display 属性的切换,内容始终存在于 DOM 中,不会因折叠而被移除。
二、CSS 深度样式定制
2.1 基础美化
通过 CSS 可以轻松美化 <details> 的外观:
details {
border: 1px solid #e2e8f0;
border-radius: 8px;
padding: 12px 16px;
margin-bottom: 12px;
background-color: #f8fafc;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.06);
transition: background-color 0.2s;
}
details:hover {
background-color: #f1f5f9;
}
details[open] {
background-color: #ffffff;
border-color: #3b82f6;
}
summary {
font-weight: 600;
font-size: 16px;
color: #1e293b;
cursor: pointer;
padding: 4px 0;
user-select: none; /* 防止双击选中文字 */
}
summary:focus-visible {
outline: 2px solid #3b82f6;
outline-offset: 2px;
border-radius: 4px;
}
2.2 自定义三角箭头
默认的三角箭头样式可以通过 ::marker 伪元素或完全自定义的方式覆盖:
方案一:修改 marker 内容
/* 方案一:修改 marker 内容 */
summary::marker {
content: '📌 ';
}
details[open] > summary::marker {
content: '📂 ';
}
方案二:完全自定义
summary {
list-style: none; /* 标准方式移除 */
}
summary::-webkit-details-marker {
display: none; /* WebKit 浏览器兼容 */
}
summary {
position: relative;
padding-left: 24px;
}
summary::before {
content: '';
position: absolute;
left: 0;
top: 50%;
transform: translateY(-50%);
width: 0;
height: 0;
border-left: 6px solid #64748b;
border-top: 5px solid transparent;
border-bottom: 5px solid transparent;
transition: transform 0.25s ease;
}
details[open] > summary::before {
transform: translateY(-50%) rotate(90deg);
}
2.3 展开与收起动画
原生 <details> 不支持高度过渡动画,以下是三种主流解决方案:
方案 A:max-height 过渡(纯 CSS)
details .content-wrapper {
max-height: 0;
overflow: hidden;
transition: max-height 0.35s ease, padding 0.35s ease;
padding: 0 16px;
}
details[open] .content-wrapper {
max-height: 800px; /* 需要预估一个足够大的值 */
padding: 12px 16px;
}<details>
<summary>带动画的折叠</summary>
<div class="content-wrapper">
<p>内容会平滑展开。</p>
</div>
</details>缺点:max-height 值需要预估,过大会导致动画速度不均匀。
方案 B:grid 行高过渡(纯 CSS,更优雅)
details .content-wrapper {
display: grid;
grid-template-rows: 0fr;
transition: grid-template-rows 0.35s ease;
overflow: hidden;
}
details[open] .content-wrapper {
grid-template-rows: 1fr;
}
details .content-wrapper > .inner {
min-height: 0;
}<details>
<summary>Grid 动画方案</summary>
<div class="content-wrapper">
<div class="inner">
<p>利用 grid-template-rows 从 0fr 到 1fr 的过渡,实现真正的高度动画。</p>
</div>
</div>
</details>这是目前纯 CSS 中最推荐的方案,无需预估高度。
方案 C:interpolate-size(实验性,未来标准)
:root {
interpolate-size: allow-keywords;
}
details .content-wrapper {
height: 0;
overflow: hidden;
transition: height 0.35s ease;
}
details[open] .content-wrapper {
height: auto;
}这是 CSS 正在推进的新特性,允许 height: 0 到 height: auto 的直接过渡。Chrome 129+ 已支持。
三、name 属性——纯 CSS 手风琴效果
HTML 规范新增的 name 属性让同名 <details> 元素互斥,打开一个时会自动关闭其他:
<div class="accordion">
<details name="faq" open>
<summary>Postman 是什么?</summary>
<div class="content-wrapper">
<div class="inner">
<p>Postman 是一个全功能的 API 开发平台,支持 API 的设计、测试、文档、监控等全生命周期管理。</p>
</div>
</div>
</details>
<details name="faq">
<summary>什么是 Collection?</summary>
<div class="content-wrapper">
...
</div>
</details>
...
</div>.accordion {
max-width: 600px;
margin: 0 auto;
}
.accordion details {
border: 1px solid #e2e8f0;
border-radius: 0;
margin-bottom: -1px; /* 合并边框 */
}
.accordion details:first-child {
border-radius: 8px 8px 0 0;
}
.accordion details:last-child {
border-radius: 0 0 8px 8px;
}
浏览器支持: Chrome 120+、Edge 120+、Safari 17.2+、Firefox 130+。
四、JavaScript 增强
4.1 toggle 事件
document.querySelectorAll('details').forEach(detail => {
detail.addEventListener('toggle', (e) => {
const isOpen = detail.open;
const summaryText = detail.querySelector('summary').textContent;
console.log(`"${summaryText}" ${isOpen ? '已展开' : '已收起'}`);
// 可用于埋点统计
analytics.track('details_toggle', {
section: summaryText,
action: isOpen ? 'expand' : 'collapse'
});
});
});4.2 程序化控制
const details = document.querySelector('details');
// 展开
details.open = true;
details.setAttribute('open', '');
// 收起
details.open = false;
details.removeAttribute('open');
// 切换
details.open = !details.open;4.3 全部展开 / 收起
function toggleAll(expand) {
document.querySelectorAll('details').forEach(d => {
d.open = expand;
});
}
// 使用
toggleAll(true); // 全部展开
toggleAll(false); // 全部收起五、无障碍(Accessibility)
<details> 天然具备良好的无障碍支持:
特性 | 说明 |
|---|---|
键盘操作 | Enter / Space 键切换展开与收起 |
Tab 导航 | <summary> 默认可聚焦 |
ARIA 角色 | 浏览器自动为 <summary> 添加 role="button" 和 aria-expanded |
屏幕阅读器 | 正确朗读展开与收起状态 |
最佳实践:
<!-- 为内容区添加 role 和 aria-label 增强语义 -->
<details>
<summary aria-label="展开查看 API 认证说明">API 认证</summary>
<div role="region" aria-label="API 认证详细说明">
<p>使用 Bearer Token 进行身份验证...</p>
</div>
</details>六、实战场景
6.1 FAQ 页面
<section class="faq">
<h2>常见问题</h2>
<details name="faq">
<summary>如何重置密码?</summary>
<p>前往设置页面,点击"安全"选项卡,选择"修改密码"。</p>
</details>
<details name="faq">
<summary>支持哪些支付方式?</summary>
<p>支持微信支付、支付宝、银行卡等主流支付方式。</p>
</details>
</section>6.2 代码片段展示
<details>
<summary>查看完整代码</summary>
<pre><code>
function debounce(fn, delay) {
let timer = null;
return function(...args) {
clearTimeout(timer);
timer = setTimeout(() => fn.apply(this, args), delay);
};
}
</code></pre>
</details>6.3 移动端纯 CSS 导航菜单
<nav>
<details>
<summary class="menu-btn">☰ 菜单</summary>
<ul class="nav-links">
<li><a href="/">首页</a></li>
<li><a href="/about">关于</a></li>
<li><a href="/contact">联系我们</a></li>
</ul>
</details>
</nav>.menu-btn {
font-size: 18px;
padding: 12px;
background: #1e293b;
color: white;
list-style: none;
}
.nav-links {
list-style: none;
padding: 0;
background: #334155;
}
.nav-links li a {
display: block;
padding: 12px 16px;
color: white;
text-decoration: none;
}
.nav-links li a:hover {
background: #475569;
}6.4 调试信息面板
<details>
<summary>🔍 调试信息(点击展开)</summary>
<table>
<tr><td>请求方法</td><td>POST</td></tr>
<tr><td>状态码</td><td>200 OK</td></tr>
<tr><td>响应时间</td><td>142ms</td></tr>
<tr><td>Content-Type</td><td>application/json</td></tr>
</table>
</details>七、浏览器兼容性
特性 | Chrome | Firefox | Safari | Edge |
|---|---|---|---|---|
<details>/<summary> | 12+ | 49+ | 6+ | 79+ |
name属性(互斥) | 120+ | 130+ | 17.2+ | 120+ |
::marker伪元素 | 86+ | 68+ | 11.1+ | 86+ |
interpolate-size | 129+ | ❌ | ❌ | 129+ |
建议访问《Can I Use》网站,以及时了解 details 属性在各类浏览器中的最新兼容性支持情况。
总结
<details> 是一个被严重低估的 HTML 原生元素,它的核心优势在于:
零依赖:无需 JavaScript 即可实现基础的折叠与展开交互。
语义化:浏览器和搜索引擎能正确理解内容结构。
无障碍友好:天然支持键盘导航和屏幕阅读器。
高度可定制:通过 CSS 可以完全改变外观,包括箭头、动画、布局 。
互斥手风琴 ——
name属性让纯 CSS 手风琴成为现实。
在实际项目中,建议优先考虑 <details> 来实现折叠交互,只有在需要复杂动画或特殊交互逻辑时才引入 JavaScript 增强。随着 interpolate-size 等新特性的推进,<details> 的动画短板也将被彻底补齐。
彩蛋
文中配有完整示例,点击《HTML <details> 元素:完整交互示例》即可查看。
