弹出式窗口 = hint

发布时间:2025 年 2 月 26 日

Chrome 133 在现有弹出式窗口功能的基础上引入了新模式:popover="hint"。这种由浏览器管理的模式支持新的堆叠上下文,可简化创建提示和类似的暂时性浮动元素。它可以减少开发者的工作量,同时保持设计灵活性。

简介和历史

借助 Chrome 114 中引入的 Popover API,您可以创建菜单和提示等无障碍浮动界面。默认情况下,popover="auto" 会为您处理轻量关闭功能和焦点管理,而无需额外的脚本编写,如介绍 Popover API 中所述。打开 popover="auto" 弹出式窗口时,所有其他非祖先 popover="auto" 弹出式窗口都会关闭,这使得 API 符合人体工学,能够执行最明智的操作。

弹出式窗口关闭其他弹出式窗口

<div id="p1" popover>First Popover</div>
<button popovertarget="p1">Open popover 1</button>
<div id="p2" popover>Second Popover</div>
<button popovertarget="p2">Open popover 2</button>

在此示例中,打开 popover 2 会关闭 popover 1,因为 popover="auto" 一次只允许打开一个此类 popover。

虽然此行为对菜单和对话框非常适用,但当需要共存多种类型的悬浮界面时,可能会造成问题。例如,如果菜单和提示框都使用 popover="auto",则可能会发生冲突,打开提示框会关闭菜单。这似乎是一种不常见的情况,但在现代应用风格的界面中经常出现。例如,github.com 标题上的菜单同时使用菜单和提示的弹出式窗口,这使得在特定条件下,这两者可以同时显示:

打开的菜单。
GitHub 菜单。

解决此问题的一种方法是为提示信息元素使用 popover="manual",这样便可通过脚本完全控制弹出式窗口。不过,这需要重新实现堆叠行为、轻量关闭和焦点管理,而这正是 Popover API 专为处理的任务。这促使我们探索扩展 API 以提供缺失的功能的方法。

通过对开发者的调研,我们发现了两种常见的堆叠情境:

  • 持久性界面:例如菜单和对话框。
  • 短暂界面:例如悬停卡片和提示。

为了同时适应这两种情况,popover="hint" 引入了与 popover="auto" 不同的第二个堆栈,确保菜单即使在显示提示时也保持打开状态。这种方法只定义了两个大类(持久性界面 [auto] 和短暂界面 [hint]),而不是为不同的界面类型引入多个堆叠上下文(这实际上会重新发明 z-index),从而在灵活性和避免重现您在使用 popover 之前遇到的问题之间取得了平衡。

新值的行为

popover="auto"popover="hint" 都支持轻触关闭,这意味着当用户点击其外部或按键盘上的 Esc 键时,它们会自动关闭。在这方面,这两种样式是完全相同的。

关于强制隐藏其他 popover,popover="auto" 在打开时会关闭所有其他 autohint popover,确保一次只有一个此类 popover 处于活动状态(嵌套的 popover 是唯一的例外情况,下文会对此进行说明)。另一方面,popover="hint" 仅会强制隐藏其他 hint 弹出式窗口,让菜单和提示仍然保持打开状态并共存。

它们最显著的区别在于嵌套行为。popover="auto" 支持嵌套,允许子窗格在另一个父窗格中保持打开状态。popover="hint" 具有特殊的嵌套行为,这正是单独的“堆栈”发挥作用的地方。当 hint 弹出式窗口位于 auto 弹出式窗口内时,它会加入 auto 堆栈以保持上下文分组,这意味着它将保持打开状态,直到其他 autohint 弹出式窗口导致其强制隐藏。这提供了直观的行为,其中提示不会中断其他菜单或弹出式窗口。

最后,对于完全不同的用例,您始终可以使用 popover="manual",它没有任何内置行为,可让您定义所需的确切功能和行为。

popover="auto" popover="hint" popover="manual"
轻关闭
强制隐藏: 无关的 autohint 不相关的 hint Nothing
嵌套: 特殊(如前所述) 不适用 - 无轻触关闭

悬停触发

一种常见的用户体验模式是,通过悬停触发来显示提示和悬停卡片。将鼠标悬停在感兴趣的元素上一段时长,系统就会显示悬停卡片。目前,需要通过 JavaScript 实现此行为,例如为 mouseentermouseleave 事件添加监听器。不过,我们正在开发另一个 API,该 API 应该可以声明式地触发悬停:Interest Invokers API

此 API 仍在开发中,但大致思路是向许多元素类型添加名为 interesttarget 的属性,以便为这些元素赋予悬停触发行为:

<a interesttarget="my-hovercard" href="...">
  Hover to show the hovercard
</a>
<span popover="hint" id="my-hovercard">
  This is the hovercard
</span> 

使用上述 HTML 时,将鼠标悬停在 <a> 链接上会自动显示 my-hovercard 弹出式窗口。将指针移出该元素后,系统会隐藏该弹出式窗口。所有这些都无需 JavaScript!

示例

<button>An interesting button</button>
<div popover="hint">More info about the button</div>
[popover] {
  margin: 0;
  inset: auto;
  position-area: bottom right;
}
const button = document.querySelector('button');
const popover = document.querySelector('[popover]');

button.onmouseenter = () => {
  setTimeout(() => {
    popover.showPopover({source: button});
  }, 500);
}

button.onmouseleave = () => {
  setTimeout(() => {
    popover.hidePopover();
  }, 500);
}
带有提示的按钮。
在线试用。

此示例使用 popover="hint" 构建一个基本提示,当用户用鼠标悬停在按钮上时,该提示会提供有关该按钮的更多信息。悬停启用由 mouseentermouseleave 的事件处理脚本提供,延迟时间为简单的 0.5 秒。请注意,此示例未处理以下一些细节:

  1. 将鼠标悬停在弹出式窗口本身上并不会阻止将鼠标悬停在触发元素上以外的位置关闭弹出式窗口。例如,您无法从弹出式窗口复制或粘贴文本。
  2. 没有“去抖动”操作:只需将鼠标悬停在按钮上几微秒的时间,即可触发弹出式窗口,即使在延迟时间过后快速移开鼠标也是如此。在这种情况下,提示信息会快速打开和关闭。
  3. 该示例完全不可访问:任何不使用鼠标的用户都无法访问提示内容。

这些缺点可以通过额外的 JavaScript 代码来修正。例如,您需要添加 focus(或者可能还需要添加 keydownkeyup) 事件处理脚本),以便支持通过键盘激活 popover。如需了解为确保可访问提示,需要正确处理哪些事项,请参阅 Sarah Higley 撰写的这篇出色的博文。所有这些问题(以及更多问题)都将由 Interest Invokers API 以声明方式自动处理。

了解详情

如需了解详情,请参阅功能说明HTML 规范