Featured image of post CSS Popover API:无需 JavaScript 的原生覆盖Featured image of post CSS Popover API:无需 JavaScript 的原生覆盖

CSS Popover API:无需 JavaScript 的原生覆盖

用于本机覆盖的 CSS Popover API。了解弹出窗口属性、弹出窗口目标、锚点定位、灯光关闭、可访问性以及与对话框和自定义模式的比较。

介绍

传统上,构建工具提示、下拉菜单和模式等叠加层需要大量 JavaScript。开发人员依赖 CSS position: absolute 进行手动坐标计算、ARIA 属性以实现可访问性,以及特定于框架的解决方案(例如 React 门户或浮动 UI)。 CSS Popover API 改变了这一点,它提供了一种原生的声明性方式来创建覆盖层,无需任何 JavaScript 即可处理定位、显示/隐藏切换、焦点管理和灯光关闭。

本文深入探讨了 Popover API,涵盖其核心属性、JavaScript 集成、样式功能、辅助功能,以及它与 <dialog> 和自定义模式等现有解决方案的比较。


1. 基础知识:popover 和 popovertarget

Popover API 引入了两个构成其基础的 HTML 属性。 popover 属性将元素标记为弹出框,而 popovertarget 将触发按钮绑定到该弹出框元素。

<button popovertarget="my-popover">Open Menu</button>
<div id="my-popover" popover>
  <p>This content appears in a native popover.</p>
</div>

单击该按钮可切换弹出窗口的可见性,无需 JavaScript。 popover 属性接受两种模式:

模式行为使用案例
占位符_0外部单击或 Escape 时灯光关闭,一次仅显示一个自动弹出窗口工具提示、下拉菜单
占位符_0必须以编程方式关闭,多个可以共存通知吐司、滑出面板

2. 弹出框切换 API

当您需要编程控制时,Popover Toggle API 在 HTMLElement 上提供了三种方法:

  • showPopover() — 显示弹出窗口
  • hidePopover() — 隐藏弹出框
  • togglePopover() — 切换可见性
const popover = document.getElementById('my-popover');
popover.showPopover();

API 还会触发两个事件:beforetoggletogglebeforetoggle 事件包括 oldStatenewState 属性,使其非常适合在可见性更改之前执行操作,例如获取动态内容或动画。

popover.addEventListener('beforetoggle', (event) => {
  if (event.newState === 'open') {
    console.log('Popover is about to open');
  }
});

3. 灯光关闭行为

自动弹出窗口可以智能地处理关闭。当用户在弹出窗口外部单击、按 Esc 键或打开另一个自动弹出窗口时,它们会自动关闭。此行为由 <dialog> 使用的相同密切观察者基础设施提供支持。

另一方面,手动弹出窗口需要通过 hidePopover()popovertarget 显式关闭。这使得它们适合类似模态的交互,其中用户必须在覆盖层关闭之前完成操作。

<button popovertarget="toast" popovertargetaction="show">Show Toast</button>
<div id="toast" popover="manual">Action completed!</div>

popovertargetaction 属性允许您指定 "show""hide" 或默认 "toggle" 行为。


4. 锚点定位

Popover API 与 CSS Anchor Positioning API 自然集成,在大多数用例中无需使用 Popper.js 或浮动 UI 等库。

.popover {
  position-anchor: --trigger;
  inset-area: block-end;
}
<button id="trigger" popovertarget="tooltip">Hover me</button>
<div id="tooltip" popover class="popover" anchor="trigger">Tooltip content</div>

anchor 属性将弹出窗口绑定到其触发器,而 inset-areaposition-fallback 等 CSS 属性控制弹出窗口的显示位置。如果弹出窗口溢出视口,它会自动翻转到另一侧——这种行为以前需要 JavaScript 来检测和调整。


5. 样式和动画

弹出框在顶层渲染,这意味着无论 z-index 如何,它们都会出现在其他所有内容之上。这消除了堆栈上下文管理的需要。

使用 ::backdrop 伪元素来设置弹出框后面区域的样式:

[popover]::backdrop {
  background: rgba(0, 0, 0, 0.3);
}

[popover]:popover-open 伪类在弹出窗口可见时将其作为目标,从而启用基于过渡的动画。但是,由于弹出窗口在 display: nonedisplay: block 之间切换,因此默认情况下,显示更改的 CSS 转换不起作用。使用 @starting-styleoverlay 属性解决此问题:

@starting-style {
  [popover]:popover-open {
    opacity: 0;
    translate: 0 -10px;
  }
}
[popover]:popover-open {
  opacity: 1;
  translate: 0 0;
  transition: opacity 0.3s, translate 0.3s, overlay 0.3s allow-discrete;
}

6. 辅助功能

Popover API 自动处理许多可访问性问题。它分配适当的隐式角色(groupdialog 取决于上下文),在弹出窗口打开时将焦点移动到弹出窗口,将焦点捕获在自动弹出窗口中,并处理 Escape 键解除。

对于其他上下文,请使用 aria-describedby 将弹出窗口链接到其触发器描述,或者当弹出窗口内容缺少可见标题文本时使用 aria-label

<button popopertarget="help" aria-describedby="help">Help</button>
<div id="help" popover role="tooltip">Press Escape to close this tip.</div>

如果弹出窗口用作菜单,请显式设置 role="menu" 并使用 aria-activedescendant 进行键盘导航。


7. Popover 与 <dialog> 与自定义模态框

特色弹出框 API占位符_0定制模态
轻解雇内置(自动)手动实施手动实施
顶层是的是,通过 showModal()通过门户或 z-index
需要JS打开没有是 (show()/showModal())是的
焦点捕捉自动弹出窗口模态对话框定制实施
最适合工具提示、菜单、吐司确认书、表格复杂的框架管理覆盖

对于需要捕获焦点的模态表单和确认,请选择 <dialog>。使用 Popover 进行轻量级、非模态叠加。当您需要框架管理的状态或复杂的编排时,自定义模式仍然有用。


8. 浏览器支持和 Polyfill

Chrome 114+、Edge 114+、Firefox 125+ 和 Safari 17+ 支持 Popover API。特征检测很简单:

if (typeof HTMLElement.prototype.showPopover === 'function') {
  // Popover API is supported
}

对于不支持的浏览器,@oddbird/popover-polyfill 提供后备。请注意,polyfill 无法完全复制 ::backdrop 或顶层行为,而是使用 position: fixed 代替。


结论

CSS Popover API 标志着声明式 UI 开发向前迈出了重要一步。通过处理显示/隐藏切换、灯光关闭、焦点管理和本机定位,它消除了在各种覆盖用例中对 JavaScript 的需求。与 CSS 锚点定位相结合,它为工具提示、下拉菜单、Toast 通知和上下文菜单提供了坚实的基础。

对于超出 API 范围的复杂场景(例如多步骤模式或框架管理的门户),现有的 JavaScript 解决方案仍然很有价值。但对于大多数叠加模式来说,Popover API 是更简单、更易于访问且性能更高的选择。