Menu

HTML details 和 summary:可折叠内容

<details> 和 <summary> 元素无需 JavaScript 就能做出可折叠区域:summary 始终可见,点击它就能显示或隐藏其余内容。学习标记写法、open 和 name 属性、手风琴、箭头样式以及 toggle 事件。

本页包含可运行的编辑器。编辑、运行,立即查看输出。

用 details 和 summary 做可折叠内容

用 <details> 包住内容,并把 <summary> 放在最前面。summary 始终可见,其余内容在读者点击之前都是隐藏的:

点击问题就能展开,再点一次就会收起。浏览器会添加三角标记,让 summary 可以获得焦点,支持用 Enter 或空格键切换,并告诉屏幕阅读器它当前是展开还是收起。整个过程不涉及任何 JavaScript。

如果省略 <summary>,浏览器会显示一个默认标签(英文中是 “Details”)。

默认展开

布尔属性 open 让内容一开始就显示出来。读者切换时,浏览器会添加和移除 open,所以它也是设置样式的抓手:

展开的那一项因为 details[open] 有了蓝色边框。展开 “Returns”,它也会变蓝;两项可以同时展开。

手风琴:一次只展开一项

给几个 <details> 元素设置相同的 name,它们就成为一个互斥组:打开一个,其他的就会关闭。这在以前需要 JavaScript,现在在最新的 Chrome、Edge、Firefox 和 Safari 中只靠这个属性就能实现:

展开第二个问题,第一个就会收起。去掉 name 属性,它们又会各自独立展开。互斥手风琴会隐藏读者可能想对比的内容,所以在各个区域互为替代时使用它;如果读者可能想同时展开几项,就用普通的 <details>。

设置标记的样式

三角形是 summary 上的列表标记。list-style: none 会去掉它(::-webkit-details-marker 规则负责 Safari),再用伪元素画出你自己的指示符:

区域展开时,加号会旋转 45 度变成叉号。要像这里的 :focus-visible 轮廓一样保留可见的焦点样式:一旦去掉默认标记,键盘用户就只能靠焦点环来定位了。

toggle 事件和 open 属性

JavaScript 可以读取和设置 details.open,每次状态变化后都会触发 toggle 事件,无论是点击、按键还是脚本引起的:

“Expand all” 会给两项都设置 open,日志显示最后一次 toggle 事件。这个事件不会冒泡,所以要在每个 <details> 元素上监听,而不是在父元素上监听。

summary 里能放什么

summary 里可以放文字、行内元素;如果这个区域的标题属于页面大纲,也可以放一个标题:

<details>
  <summary><h3>Refund policy</h3></summary>
  <p>...</p>
</details>

不要在 <summary> 中放链接、按钮和表单字段:summary 本身已经是一个控件,里面再放控件很容易被忽略或误点,屏幕阅读器对嵌套控件的朗读效果也很差。把交互内容放在 <details> 的正文中。

常见错误

  • 用 <div> 和 JavaScript 自己做切换。 <details> 已经处理好了点击、按键和屏幕阅读器状态。确实需要自定义切换时,请用带 aria-expanded 的按钮。
  • 没把 <summary> 放在最前面。 它必须是 <details> 的第一个子元素。
  • 隐藏了标记却没有替代品。 给读者一些提示,让他们知道 summary 可以展开,比如上面的加号。
  • 用 display 隐藏内容。 请切换 open;强制显示或隐藏内容的 CSS 会和浏览器的状态冲突。
  • 对需要比较的内容使用互斥组。 只有在一次展开一个区域合理时才使用 name。

常见问题

HTML 中的 details 和 summary 有什么作用?

<details> 创建一个展开收起控件:一个可以打开和关闭的区域。它的第一个子元素 <summary> 是始终可见的标签;点击它(或在它获得焦点时按 Enter 或空格键)就会显示或隐藏 <details> 中的其余内容。

怎样让 details 元素默认展开?

加上布尔属性 open:<details open>。用户切换时,浏览器会自动添加和移除这个属性,所以 CSS 可以给 details[open] 设置样式。

怎样做一次只能展开一项的手风琴?

给同一组中的每个 <details> 设置相同的 name 属性,例如 name="faq"。打开其中一个,同组的其他项就会关闭,完全不需要 JavaScript。

怎样去掉或修改 details summary 的箭头?

给 summary 设置 list-style: none,并为 Safari 加上 summary::-webkit-details-marker { display: none; }。然后画出自己的指示符,例如用 summary::after,再用 details[open] summary::after 改变它。

能检测到 details 元素被打开吗?

能。在 <details> 元素上监听 toggle 事件,并读取它的 open 属性。在 JavaScript 中设置 details.open = true 就能打开它。

Coddy 编程语言插图

和 Coddy 一起学编程

开始