☰
HTML——那些自带交互特征的HTML元素(details标签、dialog标签)
2026/9/26 11:14:00 网站建设 项目流程

那些自带交互特征的HTML元素

    • 1、非常实用的`<details>`元素
      • 1.1、黄金搭档`<summary>`元素
      • 1.2、样式的自定义
      • 1.3、实际使用案例示意
        • 1.3.1、悬浮菜单,自定义下拉框等效果
        • 1.3.2、多项菜单折叠效果
        • 1.3.3、多级嵌套的树形菜单效果
      • 1.4、全新的name属性与手风琴效果
    • 2、深入了解`<dialog>`元素和popover属性
      • 2.1、`<dialog>`元素的基本特性
      • 2.2、`<dialog>`元素的不可替代性
        • 2.2.1、`<form>`元素与对话框自动关闭
        • 2.2.2、关闭来源的判断
        • 2.2.3、自动聚焦特性
        • 2.2.4、showModal()方法与真正的对话框
        • 2.2.5、焦点隔离特性
        • 2.2.6、顶层特性
        • 2.2.7、自动层级特性
      • 2.3、原生弹层与popover属性
        • 2.3.1、popover属性的基本使用
        • 2.3.2、原生弹层相关的属性和方法
        • 2.3.3、popover属性模拟移动端下拉框

1、非常实用的<details>元素

据我所知,在所有的HTML元素中,最实用的莫过于<details>元素,其可以实现几乎任意的通过点击行为触发的展开与收起效果。

1.1、黄金搭档<summary>元素

<details>元素通常和<summary>元素同时使用,注意这里的说法—“通常”​,这是非常严谨的表述,因为<summary>元素缺省的时候浏览器会自动生成<summary>元素,并不会影响<details>元素的交互行为。此特性会在后面进一步详述,现在,我们先将精力放在<details>元素的常规应用上。

先看下面这段HTML代码:

上面的代码在浏览器中的效果如图所示(样式会因浏览器厂商及版本的不同而有所差异,此效果仅供参考)​。

上面的示例代码中出现了3个HTML元素和1个HTML属性,其中:

  • <details>元素是整个交互的核心,即使没有设置<summary>元素,也可以通过切换open属性决定里面内容的显示与隐藏。
  • <summary>元素表示摘要,是点击行为的触发源,也就是在默认情况下,我们通过点击<summary>元素来影响交互行为的发生。
  • <p>元素在这里没有任何特殊的含义,可以换成任意的内容元素,甚至可以是纯文本,例如,下面的HTML结构也是合法的:
  • open属性的存在与否决定了<details>元素是展开状态的还是收起状态的,在本例中,如果没有设置open属性,那么最终的样式效果会如图所示,小三角图标朝右,只显示<summary>元素,其余内容均隐藏。

    最后,再看一下没有设置<summary>元素的样式效果,测试代码如下所示:

    此时,在我的Chrome 117版本下会有如图3-3所示的效果,即浏览器自动生成了一个文案是“详情”​(以前的文案是“详细信息”​)的<summary>元素。

    然而,浏览器自动创建的<summary>元素是写在ShadowDOM中的(如图所示)​,外部的CSS无法改变其样式。

    因此,在实际开发中,如果你不希望出现<summary>元素,可以这么处理:自己写一个空的<summary>元素,然后设置其隐藏,就像下面这样。


对于上述HTML示例的实际渲染效果,大家可以通过在浏览器中输入地址https://www.htmlapi.cn/3/1-1.html访问来体验。

1.2、样式的自定义

浏览器默认的黑色小三角图形略显粗糙,在对视觉要求较高的产品中,往往需要对这个小图标做样式自定义。

以下所有场景均使用同样的HTML结构:

  • 1.颜色的改变
    首先,我们可以轻松改变小三角的颜色,例如,下面的CSS代码可以将小三角图标的颜色变为红色。

    效果如图所示。
  • 2.位置的改变
    其次,我们还可以将小三角图标的位置调整到右侧。

    效果如图所示。
  • 3.三角字符替换
    再者,我们还可以将小三角图标替换为其他字符,甚至是emoji字符,例如:

    此时,详情信息展开和收起的效果如图所示。

    不过需要注意的是,直接使用content替换默认三角字符的做法在Safari 16版本中并不支持,以后可能会支持,因此,如果你有兼容性的要求,可以试试使用下面的完全自定义方法。
  • 4.小三角图标完全自定义
    最后,我们还可以将小三角图标完全自定义,方法是隐藏浏览器原生的标记符,再使用::before或::after伪元素模拟,例如:

    效果如图所示。

    以上所有自定义案例均可以通过在浏览器中输入地址https://www.htmlapi.cn/3/1-1.html访问来体验。

1.3、实际使用案例示意

样式可任意自定义,那岂不意味着平日里那些通过点击行为触发的展开与收起效果都可以使用纯HTML代码实现了?还真是这样的!

1.3.1、悬浮菜单,自定义下拉框等效果

只要是点击行为触发的悬浮菜单,或者是自定义的下拉框效果,都可以使用<details>/<summary>元素实现。参考如下所示的HTML代码:

此时,只需要设置<menu>元素绝对定位,悬浮菜单效果就可以实现了,如图所示。

1.3.2、多项菜单折叠效果

在有些产品中,侧边栏菜单数量会很多,因此会有展开与收起的效果,此时,非常适合使用<details>/<summary>元素来实现,例如,下面的HTML代码:


无须使用任何额外的JavaScript代码,各个菜单项天然支持展开和收起,下图所示的就是“关注中心”收起,其他菜单项展开的效果。另外,如果希望每次最多只展开一个菜单项,可以给<details>元素设置相同的name属性值。

1.3.3、多级嵌套的树形菜单效果

<details>元素还支持嵌套,且没有层级限制,因而使用<details>/<summary>元素实现树形菜单效果也不在话下。

例如,下面的HTML代码:


然后,我们只需要给嵌套的<details>元素设置合适的缩进,再自定义<summary>元素的小三角图标,就可以实现最终的效果了,如图所示。

以上所有演示案例的交互效果以及完整代码均可以通过在浏览器中输入地址https://www.htmlapi.cn/3/1-3.html访问来体验。

总而言之一句话,<details>元素非常实用,是所有HTML元素中为数不多的和点击交互强相关的元素。

1.4、全新的name属性与手风琴效果

Chrome和Safari浏览器给<details>元素新增了name属性,这个属性的作用是,如果多个<details>元素设置了相同的name属性值,则这些<details>元素之间会形成互斥关系,即同一时间只有一个<details>元素可以展开,其他的<details>元素会自动收起。

这个特性非常适合实现手风琴效果,例如,下面的HTML代码:

此时,<details>元素每次最多只有一个是展开的,效果如图所示。

这是很棒的特性,静待现代浏览器全面支持。

2、深入了解<dialog>元素和popover属性

本节讲讲原生的对话框元素<dialog>及可以让元素以弹出框(下面简称弹框)形式显示的popover属性。

可以这么说,只要你的项目没有兼容性方面的顾虑,那么凡是对话框效果,使用<dialog>元素一定是最佳解决方案,任何使用<div>元素模拟的对话框组件都无法与之匹敌。

2.1、<dialog>元素的基本特性

<dialog>对话框的主体内容可以是任何HTML元素,甚至是其他<dialog>元素。

参见如下所示的极简案例,<dialog>元素里面有一张<img>图片,同时设置了open属性,此时,在Chrome浏览器下就可以看到如图所示的效果(不同的浏览器下<dialog>对话框的默认样式细节会有所差异)​。

在默认状态下,对话框元素会有黑色的边框、一定的padding内间距、绝对定位且左右居中,但是并没有垂直居中,这是个值得一提的细节知识,即如果我们使用open属性或者使用dialog.open()方法打开对话框,则对话框默认并不是在屏幕的垂直中心位置,而是在<dialog>元素所在的DOM树位置附近。

这么设计很好理解,例如点击某个按钮然后显示对话框,可以把对话框元素放在按钮的附近,这样对话框显示的时候和交互元素距离近,用户体验会更好。

如果我们想要对话框位于屏幕的中心,则需要额外的CSS设置或者用其他方法打开对话框,这一点会在后面介绍。

以上就是<dialog>元素的基本特性,看起来似乎也没什么,就多了些内置的CSS样式,有些CSS样式是有用的,例如绝对定位,有些CSS样式则多余,例如黑色的边框,因为与目前的主流设计风格严重不符,所以一定会被重置。

要想在实际项目中使用<dialog>元素,一定要进行样式自定义,同时还需要增加标题及关闭按钮等元素。

咦?使用<div>元素模拟的弹框不也同样是样式自定义和增加一些固定的元素吗?如此看来,使用<dialog>元素模拟对话框和使用<div>元素岂非并无区别,那还有使用<dialog>元素的必要吗?

有必要,太有必要了!

因为<dialog>元素尚有很多其他元素无可替代的实用特性。

2.2、<dialog>元素的不可替代性

2.2.1、<form>元素与对话框自动关闭

对话框元素中往往都会有一两个按钮不参与任何业务逻辑处理,其作用仅仅是关闭对话框,例如Alert类型对话框的确认按钮,或者是对话框右上角的图标字样的关闭按钮。

在过去,这种关闭行为的实现一定是使用JavaScript代码触发的。例如:

或者:

等方法。

实际上,元素内置了一种特性,就算不使用JavaScript代码,也能触发对话框的关闭,比如如下所示的HTML代码:


此时,点击“我知道了”按钮,对话框就会立即关闭。

就是这么神奇,不信你可以在浏览器中输入地址https://www.htmlapi.cn/3/2-1.html访问来体验对应的演示页面。

点击如图所示的按钮,可以看到对话框关闭了。

此效果实现的关键是在<form>元素上设置了method=“dialog”,这是个表单新特性,当设置了此声明后,在提交表单元素的时候,不再刷新页面或打开新窗口,而是关闭当前的<dialog>对话框元素。

而点击按钮触发表单提交的只能是’submit’性质的按钮,因此,万万不可将“我知道了”按钮设置为type="button"或者type=“reset”。另外,还可以在’submit’性质的按钮上设置formmethod="dialog"实现同样的对话框关闭效果,例如:

2.2.2、关闭来源的判断

<dialog>元素的DOM对象上支持一个名为returnValue的属性,可以自动或手动设置对话框关闭行为的来源。

例如下面这个例子:

这段代码模拟Confirm类型的对话框,点击“确定”按钮会执行一段业务逻辑,然后关闭对话框,点击“取消”按钮则直接关闭对话框。无论是哪个按钮,最终都有关闭对话框这一行为,如果希望区分是哪个按钮触发的关闭,就可以使用这个returnValue属性。

其中有两种给returnValue属性传值的方法:

  • 如果点击按钮触发了对话框关闭,则可以在按钮上设置value属性,例如value=“cancel”;
  • 如果使用JavaScript代码触发了对话框关闭,则可以通过给close()方法传参的方式达到我们希望的效果,例如:

    此时,我们通过访问dialog.returnValue就可以知道哪个按钮触发了对话框关闭。

眼见为实,你可以通过在浏览器中输入地址https://www.htmlapi.cn/3/2-2.htm访问来体验。

例如,点击“取消”按钮后,页面上就会提示returnValue的值是’cancel’,效果如图所示。

如果是通过其他方式关闭的,例如按下ESC快捷键,则returnValue的值会是空字符串。

2.2.3、自动聚焦特性

使用原生HTML元素作为前端组件的好处之一就是无障碍访问天然支持,无需额外的自定义。

比如这里的自动聚焦特性。

所谓“自动聚焦”​,指的是对话框显示后,浏览器的焦点会自动聚焦到对话框内。

这种特性不仅有助于增强用户体验,还保证了键盘的无障碍访问能力。

还以上面出现过的那段HTML代码为例:


此时,如果我们使用dialog.show()方法让对话框显示,则其中的<input>输入框会自动获取焦点,无须用户再去点击聚焦,效果如图所示。


类似地,如果是一个Alert提示对话框,则焦点会自动聚焦在“确定”按钮上,此时用户只需要按下回车键,对话框就会关闭,操作非常便捷,无须移动光标到“确定”按钮上,然后再点击。

需要注意的是,这种自动聚焦特性会自动聚焦第一个能够聚焦的元素,而不是智能识别是输入框还是按钮,例如下面这段内容:

此时,对话框打开的焦点则在<a>元素上,不过不要紧,要想聚焦到按钮上,按下Tab键往后索引一下就好了。

这是很多对话框组件所缺失的能力,即忽略键盘的无障碍访问。设想一下,如果对话框打开后,浏览器的焦点不在对话框之中,那么用户想要使用键盘访问对话框里面的内容就会很麻烦,不知道按下多少次的Tab键才能转入对话框元素中​。

这里还有一个细节需要注意,<dialog>元素的焦点聚焦特性只有在执行show()或showModal()方法的时候才会触发,如果是使用其他方法让对话框显示的,如以下代码所示,均无法自动聚焦到对话框中。


最后,如果对话框自动聚焦了,那么对话框关闭的时候,焦点会恢复到对话框显示之前的状态,不会影响正常的键盘访问。

2.2.4、showModal()方法与真正的对话框

前面几节虽然一直在说“对话框”​,但是最终所呈现的效果并非真正意义上的对话框,而更像弹框,层级可控,位置可变,焦点可定义,更重要的是,<dialog>元素背后的元素内容是可以正常交互的。

真正的对话框应该是足够聚焦的(用户只能专注于当前的任务)​,而不是像一个普通的绝对定位浮层。

这里就不得不提一下<dialog>元素的“王炸”方法—showModal(),让<dialog>元素成为真正的对话框元素。

还是类似的HTML代码:


然后,我们使用showModal()方法让对话框显示,此时的效果如图所示,可以明显看到多了个黑色半透明的模态层,同时除对话框元素以外的元素都无法交互了。


同时,相比show()方法,showModal()显示的对话框的定位方式也变了,不再是绝对定位,而是固定定位,且实现了真正意义上的居中效果。

上述几个明显区别参见下表。

你也可以通过在浏览器中输入地址https://www.htmlapi.cn/3/2-3.html访问来感受一下showModal()方法的样式表现。

模态对话框的半透明背景是可以使用CSS伪元素::backdrop自定义的(视频的黑色背景也可以使用此伪元素进行样式自定义)​,例如下面这段CSS代码可以让默认的10%的黑色背景变成棋盘网格,效果如图所示。



并且我们可以使用:modal伪类区分是普通对话框还是模态对话框。

当然,我对showModal()方法的评价如此之高,并不仅仅因为它多了个模态层,其还带来了现有对话框组件无法模拟的稀缺特性,且不止一个。

2.2.5、焦点隔离特性

前面提到show()方法自带聚焦特性,这个showModal()方法也有,除此之外,showModal()方法还有个焦点隔离特性。

即一旦模态对话框显示,则我们的Web页面的焦点只能出现在当前的对话框元素中,对话框之外的元素是不可能获取焦点的,哪怕使用JavaScript代码强制聚焦也不行。

也就是说整个网页中只有图所示的三个元素可以获得焦点。

此特性极为稀缺,因为如果想要使用JavaScript模拟,仅存在理论上的可能性,例如需要使用HTML inert属性让<dialog>以外的其他元素全部禁用,这实在太复杂,也不够优雅。

2.2.6、顶层特性

使用show()方法让对话框显示,对话框元素的层级是由CSS样式决定的,如果我们希望对话框元素的层级是最高的,则往往需要设置一个数值较大的z-index属性值。

而使用showModal()方法让对话框显示,对话框元素的层级自动最高,无需任何CSS样式设置,此特性被称为顶层特性,有个专门的名词描述此特性,叫作top-layer。

使用开发者工具查看<dialog>元素是可以看到此特性的,如图所示。

top-layer顶层特性实现的原理比较简单,直接在窗体之外创建一个绘制图层(如图所示)​,自然可以覆盖页面主体中的所有元素,哪怕页面中的元素的z-index值设置到无穷大也如此。


但是有时一个页面中可能不止一个<dialog>元素,如果多个模态对话框同时显示,那么层级规则又是怎样的呢?

2.2.7、自动层级特性

如果一个页面中有多个对话框通过showModal()方法显示,那么后显示的对话框层级一定最高,这一点和传统的HTML元素不同。

传统的固定定位元素,如果不专门设置层级,则一定是位于DOM树后面的元素的层级最高,而模态对话框的层级高低与DOM位置无关,与呈现的时机有关。

比如下面这个例子,页面中有两个<dialog>元素,先显示第2个<dialog>元素,再显示第1个<dialog>元素。

你会发现,如果使用的是showModal()方法,则第1个<dialog>元素的层级在上面,如图所示。


如果使用的是show()方法,则第1个<dialog>元素会在下面显示,如图所示。

眼见为实,你可以通过在浏览器中输入地址https://www.htmlapi.cn/3/2-4.html访问来体验。

综合上述7点介绍,<dialog>元素显然不是普通的<div>元素可以模拟的,无论是从用户体验的角度还是从开发成本的角度看,只要想实现对话框效果,毫无疑问,一定优先使用<dialog>元素。

2.3、原生弹层与popover属性

虽然<dialog>元素强大好用,但是对于一些需要敏捷交互的场景,它就显得有些笨重,例如当要实现点击按钮预览图片的效果时。

如果用<dialog>元素实现,那么我们需要给按钮绑定点击事件,将图片元素放在<dialog>元素之中,最后还需要专门写一个弹框关闭的方法。

在移动端开发中,由于屏幕尺寸有限,很多交互效果都是通过弹层实现的,其中有个重要的行为就是点击空白区域隐藏弹层,而<dialog>元素的模态层点击是没有隐藏行为的,因此预览图片的效果并不适合使用<dialog>元素实现。

基于种种现实的需求,一个全新的HTML属性出现了,这个属性就是popover,目前已经被各大现代浏览器支持,并且是一个全局HTML属性。所谓全局HTML属性,就是所有元素都可以设置的属性,例如id、class或性能监控相关的elementtiming属性。

有了popover属性,我们只需要使用简单的CSS和HTML代码,就可以在不使用任何JavaScript代码的情况下实现任意的基于屏幕定位的弹层效果。

2.3.1、popover属性的基本使用

popover属性的使用极为简单,使用一个简单的案例就一目了然:

给需要弹出的元素设置popover属性,给触发显示的按钮元素设置popovertarget属性,其值等同于弹出元素的id属性值即可。

此时,点击该按钮,图片就会以弹出框的形式出现,其默认样式和<dialog>元素极为相似,都有个粗的黑色边框,如图所示。

你可以通过在浏览器中输入地址https://www.htmlapi.cn/3/2-5.html访问来体验。

虽说相似,但仔细一看,在具体的细节上还是有差异的,包括:

  • popover弹层的内间距更小。
  • popover弹层默认窗体居中,且popover弹层元素是顶层元素,如图所示。
  • popover弹层默认的模态背景是透明且可穿透的,如果希望有黑色半透明背景,则需要使用::backdrop伪元素自定义,例如:
  • popover弹层内容之外的区域点击后会自动关闭当前弹层,无须额外的DOM事件支持,注意,此行为是可以自定义的。
2.3.2、原生弹层相关的属性和方法

除popover属性外,还有一些相关的属性和方法。

首先介绍一下全局属性popover的语法及几个全局的、和弹层显隐相关的API。

popover属性支持两个值,分别是’auto’和’manual’,表示弹层的隐藏是自动触发的还是手动执行的。

如果设置popover=“manual”,则弹层的隐藏需要手动执行,此属性值多用在多个弹层同时出现的场景下。

弹层的显示与隐藏除通过特定的元素外加特定的属性触发外,还可以使用下面这三个全局方法。

  • HTMLElement.hidePopover()
  • HTMLElement.showPopover()
  • HTMLElement.togglePopover()

看API名称就可以知道什么意思了,因此,不展开介绍。

接下来介绍触发弹层显示的几个HTML属性,注意,下面这两个HTML属性只能用在<button>元素和<input>元素上。

  • popovertarget:指向目标弹层元素的id属性值。如果希望知道目标弹层元素的DOM对象,可以访问当前元素对象的popoverTargetElement属性获取。
  • popovertargetaction:支持’hide’、'show或’toggle’这三个值,表示点击按钮后,弹层是显示还是隐藏,对应的DOM对象属性是popoverTargetAction。

最后,我们还可以使用CSS:popover-open伪类匹配显示中的弹层元素(不包括强制设置display:block)让弹层显示的情况,以及使用beforetoggle和toggle事件感知弹层显隐状态的变化。

2.3.3、popover属性模拟移动端下拉框

了解了popover的特性和语法,接下来就是实践环节了,看如何模拟一个在移动端很常见的、如图所示的下拉框效果。

在过去,这种效果需要耗费大量的JavaScript代码,而如今,主要的工作则是在CSS样式的设置上,包括将默认的居中效果改为居底,以及设置黑色半透明背景色。假设HTML结构如下:

其中,上半部分HTML是原生下拉框,通过覆盖一个透明度为0的按钮来触发弹层的显示,下半部分则是弹层部分,使用radio类型的选择框模拟选择行为。

接下来只需要下面几行JavaScript代码就足够了:


和过去的实现相比,简单了不知道多少个数量级,并且语义良好,性能优异,是绝对的最佳实践。

对了,差点忘记了,最终的效果你可以通过在浏览器中输入地址https://www.htmlapi.cn/3/2-6.html访问来体验。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询