pin_drop当前位置:知识文库 ❯ 图文

语义结构:HTML details与summary标签详解 - 折叠交互实现指南


教程简介

<details><summary> 是HTML5引入的一对语义化标签,用于创建可折叠/展开的内容区域。<details> 作为容器包裹可折叠的内容,<summary> 作为其可见的标题/摘要,用户点击标题即可展开或收起详细内容。这对标签无需JavaScript即可实现折叠交互,是创建FAQ、设置面板、代码示例等场景的理想选择。本教程将详细介绍这对标签的使用方法、属性、样式定制及最佳实践。

核心概念

details标签的定义

<details> 标签创建一个可折叠的部件,用户可以展开或收起其中的内容。默认状态下内容是收起的,用户点击 <summary> 可以切换显示状态。

summary标签的定义

<summary> 标签是 <details> 的可见标题/摘要,用户点击它可以切换 <details> 内容的展开/收起状态。如果没有 <summary>,浏览器会显示默认的"详细信息"文本。

交互特性

特性 说明
默认状态 内容收起(不可见)
交互方式 点击summary切换展开/收起
无需JS 原生HTML实现折叠交互
键盘支持 支持Enter和Space键切换
辅助技术 屏幕阅读器会播报展开/收起状态

典型应用场景

场景 示例
FAQ 常见问题与答案
代码示例 可折叠的代码展示
设置面板 可折叠的配置选项
帮助文档 可折叠的操作说明
附加信息 可折叠的补充内容
隐私声明 可折叠的法律条款
评论回复 可折叠的回复列表

语法与用法

基本语法

代码示例

<details>
  <summary>点击展开的标题</summary>
  <!-- 折叠的详细内容 -->
</details>

details属性

属性 类型 说明 示例
open Boolean 控制内容是否展开 <details open>
class String 指定CSS类名 class="faq-item"
id String 指定唯一标识符 id="faq-1"
name String 分组名称(同组只展开一个) name="faq-group"
data-* String 自定义数据属性 data-category="general"

summary属性

属性 类型 说明 示例
class String 指定CSS类名 class="faq-question"
id String 指定唯一标识符 id="question-1"

嵌套规则

规则 说明
details的父元素 任何流内容元素
details的子元素 <summary> 和流内容元素
summary的父元素 只能是 <details>
summary的位置 <details> 的第一个子元素
summary的数量 每个 <details> 最多一个
可嵌套 <details> 可以嵌套在另一个 <details>

代码示例

示例1:FAQ页面

代码示例

<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>FAQ页面示例</title>
  <style>
    * {
      margin: 0;
      padding: 0;
      box-sizing: border-box;
    }

    body {
      font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
      line-height: 1.6;
      color: #333;
      background: #f5f5f5;
      padding: 2rem;
    }

    main {
      max-width: 800px;
      margin: 0 auto;
    }

    h1 {
      font-size: 2rem;
      color: #2c3e50;
      margin-bottom: 0.5rem;
    }

    .subtitle {
      color: #7f8c8d;
      margin-bottom: 2rem;
    }

    /* FAQ样式 */
    .faq-list {
      display: flex;
      flex-direction: column;
      gap: 0.8rem;
    }

    details {
      background: white;
      border-radius: 8px;
      box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);
      overflow: hidden;
      transition: box-shadow 0.3s;
    }

    details[open] {
      box-shadow: 0 4px 12px rgba(0, 0, 0, 0.12);
    }

    summary {
      padding: 1.2rem 1.5rem;
      cursor: pointer;
      font-weight: 600;
      color: #2c3e50;
      display: flex;
      align-items: center;
      justify-content: space-between;
      list-style: none;
      user-select: none;
      transition: background 0.2s;
    }

    summary::-webkit-details-marker {
      display: none;
    }

    summary::after {
      content: '+';
      font-size: 1.5rem;
      font-weight: 300;
      color: #3498db;
      transition: transform 0.3s;
      flex-shrink: 0;
      margin-left: 1rem;
    }

    details[open] summary::after {
      content: '&minus;';
    }

    summary:hover {
      background: #f8f9fa;
    }

    summary:focus {
      outline: 2px solid #3498db;
      outline-offset: -2px;
      border-radius: 8px;
    }

    .faq-answer {
      padding: 0 1.5rem 1.2rem;
      color: #555;
      line-height: 1.8;
      border-top: 1px solid #f0f0f0;
      padding-top: 1rem;
    }

    .faq-answer p {
      margin-bottom: 0.5rem;
    }

    .faq-answer a {
      color: #3498db;
    }
  </style>
</head>
<body>
  <main>
    <h1>常见问题</h1>
    <p class="subtitle">以下是用户最常提出的问题及解答</p>

    <div class="faq-list">
      <details>
        <summary>如何注册账号?</summary>
        <div class="faq-answer">
          <p>点击页面右上角的"注册"按钮,填写邮箱地址和密码即可完成注册。注册成功后,您将收到一封验证邮件,请点击邮件中的链接完成邮箱验证。</p>
          <p>如果您没有收到验证邮件,请检查垃圾邮件文件夹,或<a href="#">联系客服</a>获取帮助。</p>
        </div>
      </details>

      <details>
        <summary>支持哪些支付方式?</summary>
        <div class="faq-answer">
          <p>我们目前支持以下支付方式:</p>
          <ul>
            <li>支付宝</li>
            <li>微信支付</li>
            <li>银行卡(借记卡/信用卡)</li>
            <li>PayPal</li>
          </ul>
        </div>
      </details>

      <details>
        <summary>如何申请退款?</summary>
        <div class="faq-answer">
          <p>在订单详情页面点击"申请退款"按钮,填写退款原因后提交申请。我们将在3个工作日内审核您的退款请求,审核通过后退款将在5-7个工作日内原路返回。</p>
        </div>
      </details>

      <details>
        <summary>数据是否安全?</summary>
        <div class="faq-answer">
          <p>我们非常重视数据安全。所有数据传输均使用SSL加密,存储数据采用AES-256加密算法。同时,我们定期进行安全审计和渗透测试,确保系统安全可靠。</p>
        </div>
      </details>

      <details open>
        <summary>如何联系客服?</summary>
        <div class="faq-answer">
          <p>您可以通过以下方式联系我们的客服团队:</p>
          <ul>
            <li>在线客服:工作日 9:00-18:00</li>
            <li>客服邮箱:support@example.com</li>
            <li>客服热线:400-123-4567</li>
          </ul>
        </div>
      </details>
    </div>
  </main>
</body>
</html>

示例2:代码展示与设置面板

代码示例

<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>代码展示与设置面板示例</title>
  <style>
    * { margin: 0; padding: 0; box-sizing: border-box; }
    body { font-family: sans-serif; line-height: 1.6; color: #333; background: #f5f5f5; padding: 2rem; }

    main { max-width: 800px; margin: 0 auto; }
    h1 { font-size: 1.8rem; color: #2c3e50; margin-bottom: 1.5rem; }
    h2 { font-size: 1.3rem; color: #34495e; margin: 2rem 0 1rem; }

    /* 代码展示 */
    .code-details {
      background: white;
      border-radius: 8px;
      overflow: hidden;
      margin-bottom: 1rem;
      box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);
    }

    .code-details summary {
      padding: 0.8rem 1.2rem;
      background: #2c3e50;
      color: #ecf0f1;
      cursor: pointer;
      font-family: monospace;
      font-size: 0.9rem;
      list-style: none;
      display: flex;
      align-items: center;
      gap: 0.5rem;
    }

    .code-details summary::-webkit-details-marker {
      display: none;
    }

    .code-details summary::before {
      content: '▶';
      font-size: 0.7rem;
      transition: transform 0.2s;
    }

    .code-details[open] summary::before {
      transform: rotate(90deg);
    }

    .code-details pre {
      background: #1e1e1e;
      color: #d4d4d4;
      padding: 1.2rem;
      font-family: "Consolas", monospace;
      font-size: 0.85rem;
      line-height: 1.6;
      overflow-x: auto;
    }

    /* 设置面板 */
    .settings-panel {
      background: white;
      border-radius: 8px;
      overflow: hidden;
      box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);
    }

    .settings-panel details {
      border-bottom: 1px solid #f0f0f0;
    }

    .settings-panel details:last-child {
      border-bottom: none;
    }

    .settings-panel summary {
      padding: 1rem 1.5rem;
      cursor: pointer;
      font-weight: 600;
      color: #2c3e50;
      list-style: none;
      display: flex;
      align-items: center;
      gap: 0.8rem;
      transition: background 0.2s;
    }

    .settings-panel summary::-webkit-details-marker {
      display: none;
    }

    .settings-panel summary::before {
      content: '▶';
      color: #3498db;
      transition: transform 0.2s;
    }

    .settings-panel details[open] summary::before {
      transform: rotate(90deg);
    }

    .settings-panel summary:hover {
      background: #f8f9fa;
    }

    .settings-content {
      padding: 1rem 1.5rem 1.5rem;
      color: #555;
    }

    .setting-item {
      display: flex;
      justify-content: space-between;
      align-items: center;
      padding: 0.5rem 0;
    }

    .setting-item label {
      font-size: 0.9rem;
    }

    .toggle {
      position: relative;
      width: 44px;
      height: 24px;
    }

    .toggle input {
      opacity: 0;
      width: 0;
      height: 0;
    }

    .toggle-slider {
      position: absolute;
      cursor: pointer;
      top: 0; left: 0; right: 0; bottom: 0;
      background: #ccc;
      border-radius: 24px;
      transition: background 0.3s;
    }

    .toggle-slider::before {
      content: '';
      position: absolute;
      height: 18px;
      width: 18px;
      left: 3px;
      bottom: 3px;
      background: white;
      border-radius: 50%;
      transition: transform 0.3s;
    }

    .toggle input:checked + .toggle-slider {
      background: #3498db;
    }

    .toggle input:checked + .toggle-slider::before {
      transform: translateX(20px);
    }
  </style>
</head>
<body>
  <main>
    <h1>开发文档</h1>

    <h2>代码示例</h2>

    <details class="code-details">
      <summary>example.js - 基础配置</summary>
      <pre><code>// 基础配置
const config = {
  apiUrl: 'https://api.example.com',
  timeout: 5000,
  retryCount: 3,
  debug: false
};

export default config;</code></pre>
    </details>

    <details class="code-details">
      <summary>utils.js - 工具函数</summary>
      <pre><code>// 防抖函数
function debounce(fn, delay = 300) {
  let timer = null;
  return function(...args) {
    clearTimeout(timer);
    timer = setTimeout(() => fn.apply(this, args), delay);
  };
}</code></pre>
    </details>

    <h2>系统设置</h2>

    <div class="settings-panel">
      <details open>
        <summary>通知设置</summary>
        <div class="settings-content">
          <div class="setting-item">
            <label>邮件通知</label>
            <div class="toggle">
              <input type="checkbox" checked>
              <span class="toggle-slider"></span>
            </div>
          </div>
          <div class="setting-item">
            <label>推送通知</label>
            <div class="toggle">
              <input type="checkbox">
              <span class="toggle-slider"></span>
            </div>
          </div>
        </div>
      </details>

      <details>
        <summary>隐私设置</summary>
        <div class="settings-content">
          <div class="setting-item">
            <label>公开个人资料</label>
            <div class="toggle">
              <input type="checkbox" checked>
              <span class="toggle-slider"></span>
            </div>
          </div>
          <div class="setting-item">
            <label>允许搜索引擎索引</label>
            <div class="toggle">
              <input type="checkbox">
              <span class="toggle-slider"></span>
            </div>
          </div>
        </div>
      </details>
    </div>
  </main>
</body>
</html>

示例3:手风琴效果(使用name属性)

代码示例

<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>手风琴效果示例</title>
  <style>
    * { margin: 0; padding: 0; box-sizing: border-box; }
    body { font-family: sans-serif; line-height: 1.6; color: #333; padding: 2rem; }

    main { max-width: 700px; margin: 0 auto; }
    h1 { font-size: 1.8rem; color: #2c3e50; margin-bottom: 1.5rem; }
    p { margin-bottom: 1.5rem; color: #666; }

    .accordion {
      display: flex;
      flex-direction: column;
      gap: 0.5rem;
    }

    details {
      background: white;
      border: 1px solid #e0e0e0;
      border-radius: 6px;
      overflow: hidden;
      transition: border-color 0.3s;
    }

    details[open] {
      border-color: #3498db;
    }

    summary {
      padding: 1rem 1.2rem;
      cursor: pointer;
      font-weight: 600;
      color: #2c3e50;
      list-style: none;
      display: flex;
      align-items: center;
      gap: 0.8rem;
      transition: background 0.2s;
    }

    summary::-webkit-details-marker { display: none; }

    summary::before {
      content: '';
      width: 20px;
      height: 20px;
      border-radius: 50%;
      background: #ecf0f1;
      display: flex;
      align-items: center;
      justify-content: center;
      font-size: 0.8rem;
      flex-shrink: 0;
      transition: background 0.3s;
    }

    details[open] summary::before {
      background: #3498db;
    }

    details[open] summary {
      background: #f0f7ff;
    }

    .accordion-content {
      padding: 1rem 1.2rem;
      color: #555;
      border-top: 1px solid #f0f0f0;
    }
  </style>
</head>
<body>
  <main>
    <h1>课程大纲</h1>
    <p>点击展开查看各章节的详细内容(同一时间只展开一个章节)</p>

    <div class="accordion">
      <!-- name属性实现手风琴效果:同组只展开一个 -->
      <details name="course-chapters" open>
        <summary>第一章:HTML基础</summary>
        <div class="accordion-content">
          <p>本章介绍HTML的基本概念和常用标签,包括文档结构、文本标签、链接、图片等内容。</p>
        </div>
      </details>

      <details name="course-chapters">
        <summary>第二章:CSS样式</summary>
        <div class="accordion-content">
          <p>本章讲解CSS的选择器、盒模型、布局方式等核心概念,帮助你掌握页面样式设计。</p>
        </div>
      </details>

      <details name="course-chapters">
        <summary>第三章:JavaScript编程</summary>
        <div class="accordion-content">
          <p>本章涵盖JavaScript的基础语法、DOM操作、事件处理等内容,让你能够实现页面交互。</p>
        </div>
      </details>

      <details name="course-chapters">
        <summary>第四章:项目实战</summary>
        <div class="accordion-content">
          <p>本章通过完整的实战项目,将前三章的知识综合运用,构建一个真实的Web应用。</p>
        </div>
      </details>
    </div>
  </main>
</body>
</html>

浏览器兼容性

浏览器 支持版本 name属性 备注
Chrome 12+ 120+ 完全支持
Firefox 49+ 130+ 完全支持
Safari 6+ 17.2+ 完全支持
Edge 79+ 120+ 完全支持
IE 不支持 不支持 需要polyfill
Opera 15+ 106+ 完全支持
iOS Safari 6+ 17.2+ 完全支持
Android 4.4+ 120+ 完全支持

IE兼容方案

代码示例

// 为不支持details的浏览器提供基本支持
if (!('open' in document.createElement('details'))) {
  document.querySelectorAll('details').forEach(function(details) {
    var summary = details.querySelector('summary');
    if (!summary) return;

    details.setAttribute('role', 'group');
    summary.setAttribute('role', 'button');
    summary.setAttribute('tabindex', '0');
    summary.setAttribute('aria-expanded', 'false');

    summary.addEventListener('click', function() {
      var isOpen = details.hasAttribute('open');
      details.toggleAttribute('open');
      summary.setAttribute('aria-expanded', !isOpen);
    });
  });
}

注意事项与最佳实践

1. summary必须是details的第一个子元素

代码示例

<!-- 错误:summary不是第一个子元素 -->
<details>
  <p>内容</p>
  <summary>标题</summary>
</details>

<!-- 正确:summary是第一个子元素 -->
<details>
  <summary>标题</summary>
  <p>内容</p>
</details>

2. 没有summary时浏览器会显示默认文本

代码示例

<!-- 没有summary:浏览器显示"详细信息" -->
<details>
  <p>折叠的内容</p>
</details>

<!-- 推荐:始终提供summary -->
<details>
  <summary>展开查看详情</summary>
  <p>折叠的内容</p>
</details>

3. 使用open属性默认展开

代码示例

<!-- 默认展开 -->
<details open>
  <summary>重要通知</summary>
  <p>这条信息默认展开显示</p>
</details>

4. 自定义样式时隐藏默认标记

代码示例

/* 隐藏默认三角标记 */
summary::-webkit-details-marker {
  display: none;
}

summary {
  list-style: none;
}

/* 自定义展开/收起图标 */
summary::before {
  content: '▶';
  display: inline-block;
  transition: transform 0.2s;
}

details[open] summary::before {
  transform: rotate(90deg);
}

5. 添加动画效果

代码示例

/* 内容展开动画 */
details .content {
  animation: slideDown 0.3s ease-out;
}

@keyframes slideDown {
  from {
    opacity: 0;
    transform: translateY(-10px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

代码规范示例

规范的details使用

代码示例

<!-- FAQ -->
<section aria-labelledby="faq-title">
  <h2 id="faq-title">常见问题</h2>

  <details class="faq-item">
    <summary class="faq-question">如何重置密码?</summary>
    <div class="faq-answer">
      <p>前往登录页面,点击"忘记密码"链接,输入注册邮箱后按提示操作即可。</p>
    </div>
  </details>

  <details class="faq-item">
    <summary class="faq-question">支持哪些浏览器?</summary>
    <div class="faq-answer">
      <p>我们支持Chrome、Firefox、Safari和Edge的最新两个主要版本。</p>
    </div>
  </details>
</section>

<!-- 代码展示 -->
<details class="code-block">
  <summary>查看源代码</summary>
  <pre><code>const app = createApp(App);
app.mount('#app');</code></pre>
</details>

常见问题与解决方案

常见问题

details/summary能否替代手风琴组件?

基本场景可以。<details> + <summary> 天然支持折叠交互,配合 name 属性可实现手风琴效果。但如果需要复杂的动画、嵌套或自定义交互逻辑,仍建议使用JavaScript组件。

如何监听details的展开/收起事件?

可以监听 toggle 事件,通过JavaScript为details元素添加事件监听器来获取展开/收起状态。

name属性的浏览器支持情况?

name 属性是较新的特性(2023年加入规范),Chrome 120+、Firefox 130+、Safari 17.2+ 支持。旧浏览器会忽略该属性,多个details可以同时展开。

details内可以放表格、表单等复杂内容吗?

可以。<details> 内可以放置任何流内容,包括表格、表单、图片、视频等。

如何让details展开时有平滑动画?

原生 <details> 的展开/收起没有动画。可以通过CSS动画或JavaScript实现平滑过渡。一种常用方法是在内容区域添加 fadeIn 动画。

总结

<details><summary> 标签是HTML语义化体系中的实用组合,关键要点如下:

  • 原生交互:无需JavaScript即可实现折叠/展开功能

  • 可访问性:天然支持键盘操作和屏幕阅读器

  • open属性:控制默认展开状态,也可通过JS动态控制

  • name属性:实现手风琴效果(同组只展开一个)

  • 样式定制:可以自定义标记图标和展开动画

正确使用 <details><summary> 标签,能减少对JavaScript的依赖,提升页面可访问性,是创建交互式内容的优雅方案。

小贴士

<details>name 属性是HTML规范中较新加入的特性,能够原生实现手风琴效果(同一组中只允许一个展开),这在以前必须依赖JavaScript才能实现。建议在实际项目中积极尝试使用,同时记得为不支持的旧浏览器准备降级方案。

标签: HTML details标签 summary HTML5 折叠面板 FAQ

本文涉及AI创作

内容由AI创作,请仔细甄别

list快速访问

上一篇: 语义结构:HTML figure与figcaption标签详解 - 图片说明语义化 下一篇: 语义结构:HTML dialog标签使用教程 - 模态对话框与非模态对话框详解

poll相关推荐