更多样式选项 <details>

发布时间:2024 年 11 月 6 日

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

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

浏览器支持

  • Chrome:131.
  • Edge:131.
  • 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 的录制内容

UA 样式表中 ::details-contentdisplay 类型已设为 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 */
}

为方便设置样式,内容封装在封装容器 div 中。封装容器 div 会应用布局样式(例如 padding),并且 ::details-content 伪元素会进行动画处理。