Native Overlay

Native Dialog (showModal)

使用 <dialog>.showModal()。顶层渲染 ✓,Escape 关闭 ✓,滚动锁定 ✓,::backdrop 伪元素。

Native Dialog

showModal() 自动阻止背景滚动。
试试看 — 打开后背景完全锁死。

发现: 滚动锁定开箱即用。
::backdrop 进场动画正常,退场无法动画——浏览器在 close() 时立即销毁 ::backdrop,这是 API 限制。
没有锚点定位,只能居中弹窗,不能做 dropdown/menu/popover。
floating-ui + Native Popover (left flip)

left 方向,floating-ui 自动计算位置。HTML 里通过 popovertarget 关联。

Left Positioned

floating-ui computePosition + flip + shift。
左侧空间不够时自动翻转到右边。

发现: 定位和 Light Dismiss 都解决了。
滚动锁定仍然没有 — 打开后背景继续滚。
Native Popover (popover attribute)

使用浏览器原生 popover 属性。顶层渲染 ✓,light dismiss ✓,锚点定位(需要 CSS anchor 或 JS)。

popover + floating-ui

浏览器自动 Top Layer + Light Dismiss。
floating-ui 做锚点定位 + 碰撞检测。

Top Placement

placement=top,滚动到页面底部打开试试翻转。

发现: 原生 popover 不阻止背景滚动。打开上面的 popover 然后滚动页面试试 — body 照样滚。 CSS anchor 定位完全不需要 floating-ui,但 兼容性太差(Chrome only),且没有碰撞检测。
总结对比
能力 popover dialog.showModal popover + floating-ui ark/zag + Overlay
顶层渲染 ✓ (Portal)
锚点定位 △ (CSS anchor, 受限)
碰撞检测 △ (position-try)
Light Dismiss ✓ (Escape) ✓ (机器状态管理)
滚动锁定 ✓ (preventBodyScroll)
Android 返回手势 ? ? ? ✓ (CloseWatcher)
Nested 弹层 △ (popover 是全局的) △ (不支持嵌套) ✓ (overlay stack)

结论:没有一种原生 API 能完整覆盖下拉弹层的全部需求。

  • popover 最接近,但缺 滚动锁定定位引擎复杂状态管理
  • dialog.showModal() 有滚动锁定但 不能做锚点定位,只适合模态弹窗
  • ark-ui/zag-js + 我们的 Overlay 是当前唯一覆盖所有格子的方案

未来的可能性:如果浏览器给 popover 加上 lock-scroll 属性(有提案), 再把 @position-try, anchor(), position-area 做到 floating-ui 同级的鲁棒性, 那 ark/zag 的定位层就可以被替代。但状态机层(嵌套管理、open/close 转换、键盘导航)仍然需要。