折叠面板不用 JS?`<details>` 和 `<summary>` 标签的隐藏用法

折叠面板不用 JS?<details><summary> 标签的隐藏用法

关键词: ​ HTML5、details、summary、折叠面板、无 JS、交互组件


一、前言:一个被严重低估的 HTML 标签

提到"折叠面板"或"手风琴效果",大多数前端开发者的第一反应是:

"写一堆 div,绑 onClick,用 useState 控制 isOpen......"

但你可能不知道,HTML5 早就内置了一个原生折叠组件,不需要写一行 JavaScript:

css 复制代码
<details>
  <summary>点击展开</summary>
  <p>这里是折叠的内容</p>
</details>

就这三行,一个可展开/收起的面板就完成了。

浏览器原生支持,自带动画(部分浏览器),语义清晰,可访问性满分。

今天我们就来深挖这对"冷门兄弟"------<details><summary> 的所有隐藏玩法。


二、基本用法

2.1 最简单的折叠面板

css 复制代码
<details>
  <summary>什么是 HTML5 details 标签?</summary>
  <p>
    details 是 HTML5 引入的一个原生交互元素,
    用于创建可展开/收起的披露组件。
  </p>
</details>

渲染效果:

  • 默认收起,只显示 <summary> 的内容
  • 点击 <summary> 区域,内容展开
  • 再次点击,内容收起

2.2 默认展开

加一个 open 属性即可:

css 复制代码
<details open>
  <summary>默认展开的内容</summary>
  <p>页面加载时我就是打开的。</p>
</details>

2.3 语义结构

xml 复制代码
<details>
  <summary>摘要/标题(必填,但可省略)</summary>
  <!-- summary 之后的所有内容都是可折叠区域 -->
  <p>正文内容......</p>
  <ul>
    <li>列表项</li>
    <li>列表项</li>
  </ul>
</details>

⚠️ 注意: ​ 如果省略 <summary>,浏览器会自动生成一个默认的 "Details" 文本作为标题。


三、样式定制:告别默认三角

3.1 隐藏默认标记

不同浏览器对 <summary> 的默认三角标记渲染不同。统一隐藏:

css 复制代码
summary {
  list-style: none;          /* 标准 */
}

summary::-webkit-details-marker {
  display: none;             /* Safari/Chrome */
}

3.2 自定义展开/收起图标

xml 复制代码
<details class="custom-details">
  <summary>
    <span class="title">点击展开</span>
    <span class="icon">▶</span>
  </summary>
  <p>折叠内容......</p>
</details>

<style>
  .custom-details summary {
    display: flex;
    align-items: center;
    justify-content: space-between;
    cursor: pointer;
    padding: 12px;
    background: #f5f5f5;
    border-radius: 6px;
  }

  .custom-details[open] .icon {
    transform: rotate(90deg);
  }

  .icon {
    transition: transform 0.2s ease;
  }

  .custom-details p {
    padding: 12px;
    margin: 0;
  }
</style>

3.3 用 CSS 实现平滑展开动画

<details>open 属性切换是瞬间的,没有过渡动画。但我们可以用 CSS Grid 模拟:

css 复制代码
details .content {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows 0.3s ease;
}

details[open] .content {
  grid-template-rows: 1fr;
}

details .content > div {
  overflow: hidden;
}
css 复制代码
<details>
  <summary>带平滑动画的面板</summary>
  <div class="content">
    <div>
      <p>这段内容会平滑地展开和收起。</p>
      <p>利用 CSS Grid 的 fr 动画实现。</p>
    </div>
  </div>
</details>

🎉 纯 CSS 动画,零 JavaScript!


四、实战场景

4.1 FAQ 常见问题

xml 复制代码
<section class="faq">
  <h2>常见问题</h2>

  <details>
    <summary>这个产品支持退款吗?</summary>
    <p>支持 7 天无理由退款,详情请查看退款政策。</p>
  </details>

  <details>
    <summary>如何联系客服?</summary>
    <p>请发送邮件至 support@example.com,我们会尽快回复。</p>
  </details>

  <details>
    <summary>支持哪些支付方式?</summary>
    <p>我们支持信用卡、支付宝、微信支付和 PayPal。</p>
  </details>
</section>

<style>
  .faq details {
    border-bottom: 1px solid #ddd;
    padding: 12px 0;
  }

  .faq summary {
    font-weight: 500;
    cursor: pointer;
    padding: 8px 0;
  }

  .faq p {
    margin: 8px 0 0;
    color: #666;
  }
</style>

4.2 手风琴菜单(互斥展开)

这个场景确实需要一点点 JavaScript,但极其轻量:

xml 复制代码
<details name="faq" open>
  <summary>问题一</summary>
  <p>答案一</p>
</details>

<details name="faq">
  <summary>问题二</summary>
  <p>答案二</p>
</details>

<details name="faq">
  <summary>问题三</summary>
  <p>答案三</p>
</details>
dart 复制代码
// 利用 name 属性实现互斥(实验性特性,部分浏览器支持)
// 或者手动实现:
document.querySelectorAll('details').forEach(detail => {
  detail.addEventListener('toggle', () => {
    if (detail.open) {
      document.querySelectorAll('details').forEach(d => {
        if (d !== detail) d.open = false;
      });
    }
  });
});

💡 好消息: ​ 最新的 HTML 规范正在引入 name 属性来实现原生互斥(类似 <input type="radio">),未来可能完全不需要 JS!

4.3 图片预览/隐藏剧透

xml 复制代码
<details class="spoiler">
  <summary>⚠️ 点击查看剧透</summary>
  <p>其实凶手就是那个看起来最无辜的管家。</p>
</details>

<style>
  .spoiler summary {
    color: #e74c3c;
    font-weight: bold;
  }
</style>

4.4 代码块折叠

less 复制代码
<details class="code-block">
  <summary>📄 main.js(点击展开代码)</summary>
  <pre><code>function hello() {
  console.log('Hello, World!');
}

hello();</code></pre>
</details>

非常适合技术文档、博客中的长代码段。


五、JavaScript 交互

虽然 <details> 主打"无 JS",但配合 JavaScript 可以做更多事情。

5.1 监听展开/收起事件

javascript 复制代码
const details = document.querySelector('details');

details.addEventListener('toggle', (event) => {
  if (details.open) {
    console.log('面板展开了');
  } else {
    console.log('面板收起了');
  }
});

5.2 编程式控制

ini 复制代码
// 展开
details.open = true;

// 收起
details.open = false;

// 切换
details.open = !details.open;

5.3 保存状态到 localStorage

ini 复制代码
// 读取保存的状态
const saved = localStorage.getItem('details-open');
if (saved === 'true') {
  details.open = true;
}

// 状态变化时保存
details.addEventListener('toggle', () => {
  localStorage.setItem('details-open', details.open);
});

六、可访问性(A11y)

<details><summary> 原生支持键盘交互:

操作 行为
Tab 聚焦到 <summary>
Enter / Space 切换展开/收起
屏幕阅读器 自动播报展开状态

无需额外 ARIA 属性,浏览器自动处理。这是它相比"手写 div + JS"方案的巨大优势。


七、浏览器兼容性

浏览器 支持情况
Chrome ✅ 12+
Firefox ✅ 49+
Safari ✅ 6+
Edge ✅ 79+
移动端 ✅ 全面支持

这是一个极其成熟的特性,可以放心在生产环境使用。


八、与主流方案的对比

方案 是否需要 JS 可访问性 代码量 维护成本
<details> + <summary> ❌ 不需要 ✅ 原生 ⭐ 极少 ⭐ 极低
div + onClick ✅ 需要 ⚠️ 需手动处理 ⭐⭐⭐ 较多 ⭐⭐ 中等
UI 组件库(Ant Design 等) ✅ 依赖框架 ✅ 已处理 ⭐⭐ 中等 ⭐⭐⭐ 较高

结论: ​ 如果你的需求是简单的折叠/展开,用 <details> 是最优雅的方案。复杂交互(如动画编排、异步加载内容)再考虑组件库。


九、总结

<details><summary> 是 HTML5 中被严重低估的"宝藏标签":

  • 零 JavaScript 实现折叠面板
  • 语义清晰,可访问性满分
  • 浏览器原生支持,兼容性极好
  • CSS 可深度定制,动画也能纯 CSS 实现
  • ✅ 适合 FAQ、代码折叠、剧透隐藏等场景

下次写折叠面板时,别急着 npm install 一个组件库,先想想:能不能用三行 HTML 解决?

相关推荐
Kyrie_kk21 分钟前
Java--TimeUnit时间单位枚举类(时间单位规范)
java·后端
长大198823 分钟前
旧版浏览器不兼容?一行代码引入 html5shiv 拯救你的页面
后端
大勇前进23 分钟前
Canvas 绘图初体验:用代码在网页上“画画”的魔法
后端
大黄评测24 分钟前
图文排版神器:用 `<figure>` 和 `<figcaption>` 规范你的内容结构
后端
JavaGuide2 小时前
SpaceX 工程师的 AI Coding 玩法太牛了, 200 多个 Agent 并行!
前端·后端
SQL-First布道者2 小时前
⚡Spring JDBC 完整体系 · 第 10 集 · 手搓 `BaseCondition`
java·spring boot·后端·spring·mybatis·spring jdbc
2601_962074682 小时前
Spring Boot的无缝衔接:深入解析与实践
数据库·spring boot·后端
聪明蛋子哟3 小时前
多智能体协作的三种模式:从群聊到分层,如何设计可扩展的Agent系统
后端·python·flask
DolphinDB3 小时前
告别手写代码:Trae + DolphinDB Skill,10 分钟造一个懂期货的投研 Agent
后端