更多样式选项 <details>

发布时间:2024 年 11 月 6 日

从 Chrome 131 开始,您可以使用更多选项来设置 <details><summary> 元素的结构样式。现在,您可以在构建披露或手风琴微件时使用这些元素。

具体而言,Chrome 131 中引入的更改允许在这些元素上使用 display 属性,并添加了 ::details-content 伪元素来设置展开和收起部分的样式。

Browser Support

  • Chrome: 131.
  • Edge: 131.
  • Firefox: 143.
  • Safari: 18.4.

Source

<details> 元素上设置 display

过去,无法更改 <details> 元素的显示类型。此限制现已放宽,例如,您可以在 <details> 元素上使用网格或 Flex 布局。

在以下示例中,排他性手风琴由并排放置的多个 <details> 元素组成。展开某个 <details> 元素时,其内容会放置在 <summary> 旁边。

演示

正在录制

在 Chrome 131 中录制的 https://codepen.io/web-dot-dev/pen/VwoBQjY

这是通过对 <details> 元素使用以下 CSS 来实现:

details {
  display: flex;
  flex-direction: row;
}

还允许使用其他显示值,例如 grid

关于使用 display: inline 的注意事项

可能会产生意外结果的 display 值是 inline。不是因为该功能无法正常运行,而是因为 HTML 解析器存在限制。

<details> 元素放置在段落中时,它会强制 HTML 解析器先关闭打开的段落,如 HTML 标准的第 13.2.6.4.7 节中所定义:

起始标记的标记名称为以下之一:“address”“article”“aside”“blockquote”“center”“details”“dialog”“dir”“div”“dl”“fieldset”“figcaption”“figure”“footer”“header”“hgroup”“main”“menu”“nav”“ol”“p”“search”“section”“summary”“ul”

如果打开的元素堆栈在按钮范围内包含 p 元素,则关闭 p 元素。 插入令牌的 HTML 元素。

因此,无论您是否设置了 display: inline<details> 都会沿块方向流动。

例如,以下标记

<p>Hello <details>…</details> world</p>

解析后变为:

<p>Hello </p><details>…</details> world<p></p>

您可以使用 Chrome 开发者工具检查已解析的标记,在此演示中自行查看。

请注意,这仅适用于将 <details> 嵌套在 <p> 中。在 <div> 内对 <details> 使用 display: inline 可以正常运行。

::details-content

在浏览器中,<details> 元素是使用 Shadow DOM 实现的。它包含一个用于摘要的 <slot>(具有默认摘要子项)和一个用于所有剩余内容的 <slot>,这意味着 <details> 元素的所有子项(<summary> 元素除外)。

<details>
  ↳ #shadow-root (user-agent)
      <slot id="details-summary">
        <summary>Details</summary>
        <!-- The summary goes here -->
      </slot>
      <slot id="details-content">
        <!-- All content goes here -->
      </slot>
</details>

除了在 <details> 上使用更多展示类型之外,现在还可以使用 ::details-content 伪元素定位内容 slot。您可以使用此伪类来设置封装 <details> 元素内容的容器的样式。

details::details-content {
  border: 5px dashed hotpink;
}

如需仅在 <details> 元素处于打开状态时应用设置的样式,请在 <details> 选择器前面加上 [open] 选择器。

[open]::details-content {
  border: 5px dashed hotpink;
}

建议仅当 <details> 元素处于 [open] 状态时,才对 ::details-content 伪元素应用样式。

演示

正在录制

在 Chrome 131 中录制的 https://codepen.io/web-dot-dev/pen/oNKMEYv

::details-contentdisplay 类型在 UA 样式表中设置为 block,而之前是 display: contents。在某些情况下,此项更改可能会对您不利,例如披露的内容依赖于 height: 100%。如果您遇到此问题,可以按如下方式将 display 类型重新设置为 contents 来解决此问题:details[open]::details-content { display: contents; }

::details-content 伪元素添加动画效果

您可以为 <details> 元素的内容添加动画效果,使其在展开时显示。在以下示例中,宽度从 0px 动画显示到 300px

::details-content {
  transition: width 0.5s ease, content-visibility 0.5s ease allow-discrete;
  width: 0;
}

[open]::details-content {
  width: 300px;
}

除了转换 width 之外,还需要转换 content-visibility 属性。这是因为它的值会在未打开状态和打开状态之间发生变化,如 User-Agent 样式表中定义的那样。由于该属性是可离散添加动画效果的属性,因此您需要使用 allow-discrete 关键字才能使其正常运行。

在之前分享的专属手风琴演示中添加了此功能后,结果如下所示:

演示

正在录制

在 Chrome 131 中录制的 https://codepen.io/web-dot-dev/pen/XWvBZNo

height 也可以是动画。如需将动画效果设置为 height: auto,您需要使用 interpolate-sizecalc-size()。此外,为防止内容溢出 ::details-content 伪元素,请向其应用 overflow: clip

::details-content {
    transition: height 0.5s ease, content-visibility 0.5s ease allow-discrete;
    height: 0;
    overflow: clip;
}

/* Browser supports interpolate-size */
@supports (interpolate-size: allow-keywords) {
    :root {
        interpolate-size: allow-keywords;
    }

    [open]::details-content {
        height: auto;
    }
}

/* Fallback for browsers with no interpolate-size support */
@supports not (interpolate-size: allow-keywords) {
    [open]::details-content {
        height: 150px;
        overflow-y: scroll; /* In case the contents should be taller than 150px */
    }
}

您可以在以下演示中看到代码的实际效果,该演示灵感源自 Material UI 的手风琴。每个 <details> 元素的内容都会以流畅的动画效果呈现。

演示

正在录制

在 Chrome 131 中录制的 https://codepen.io/web-dot-dev/pen/ExqpQZM

在不支持 ::details-content 的浏览器中,该组件仍可正常运行。访问者唯一看不到的是动画。

功能检测

如需检测 CSS 中是否支持 ::details-content 伪类,请使用以下代码段。

@supports selector(::details-content) {
  
}

您还可以使用此检测作为一种指示性检查,以确定访问者使用的浏览器是否支持额外的显示值。

无障碍注意事项

引入 ::details-content 伪元素和更改显示类型的能力不会影响 <details> 元素的可访问性。

与之前一样,至少在基于 Chromium 的浏览器中,并且根据 HTML 标准<details> 元素是可搜索的,并且当浏览器尝试滚动到其隐藏内容以响应网页内查找、ScrollToTextFragment 和元素 fragment 导航时,该元素会自动展开。此设置不会更改。

不过,在使用排他性手风琴之前,请考虑它对用户是有帮助还是有害。虽然使用排他性手风琴可减少内容占用的视觉空间量,但用户可能需要打开许多项才能查看所有信息。这可能会让想要同时查看多件商品的买家感到沮丧。

如何设置标记的样式?

目前,列表标记的样式设置无法互操作,因为 Gecko 和(当前)Chromium 采用了一种方法,而 WebKit(之前与 Chromium 共享)采用了另一种方法。

该功能实现互操作后,我们的目标是让您更好地控制标记的样式。

更多演示

最后,我们再为您提供一些演示供您参考。它们都使用 ::details-content

UIKit 手风琴

演示

正在录制

Chrome 131 中 https://codepen.io/web-dot-dev/pen/rNXrJyQ 的录制内容

此演示是根据 UIKit 手风琴构建的。此代码与之前分享的 Material UI 手风琴代码几乎相同。

部分打开的披露信息微件

演示

正在录制

Chrome 131 中的 https://codepen.io/web-dot-dev/pen/PoMBQmW 录制内容

此演示展示了一个部分打开的披露微件,其内容已显示在屏幕上。为此,content-visibility 始终设置为 visible。由于涉及计算,height 会使用 calc-size() 进行动画处理。

::details-content {
  content-visibility: visible; /* Make it always visible */
    
  transition: height 0.5s ease;
  height: 150px;
  overflow: clip;
}

[open]::details-content {
  height: calc-size(auto, size + 0.5rem); /* calc-size because we need to add a length */
}

为方便设置样式,内容封装在 wrapper div 中。wrapper div 会应用 padding 等布局样式,而 ::details-content 伪元素会进行动画处理。