更多样式选项 <details>

发布时间:2024 年 11 月 6 日

从 Chrome 131 开始,您可以使用更多选项来设置 <details><summary> 元素的结构样式。现在,您可以在构建展开式或折叠式 widget 时使用这些元素。

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

浏览器支持

  • Chrome:131.
  • Edge:不受支持。
  • Firefox:不受支持。
  • Safari:不受支持。

<details> 元素上设置 display

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

在以下示例中,排他式折叠菜单由几个并排放置的 <details> 元素组成。展开其中一个 <details> 元素后,其内容会放置在 <summary> 旁边。

演示

正在录制

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

这可以通过使用以下 CSS 在 <details> 元素上使用 Flex 布局来实现:

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 开发者工具检查已解析的标记,在此演示中亲自验证。

请注意,这仅适用于在 <p> 中嵌套 <details>。对 <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 伪元素定位内容槽位。您可以使用此伪元素为封装 <details> 元素内容的容器设置样式。

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

如需仅在 <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 属性还需要转换。这是因为它的值会在用户代理样式表中定义的未打开和打开状态之间切换。由于该属性是一个离散动画属性,因此您需要 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 */
}

为方便设置样式,内容封装在封装容器 div 中。封装容器 div 会应用 padding 等布局样式,并为 ::details-content 伪元素添加动画效果。