写过浮层的人都踩过这个坑——dropdown 超屏只能靠 JS 算坐标,今天 CSS 把这件事彻底原生化了

写过浮层的人大概都踩过这个坑——dropdown 写好了,但窗口缩小就超出屏幕了,只能再套一层 JS 算坐标、监听 resize、然后手动翻方向。二十年了,每次都要靠 getBoundingClientRect()Popper.js 绕一大圈。

2026 年,这件事被 CSS @position-try 用三行彻底原生化了,连监听器都不用写。

浏览器已经全面支持

截至 2026 年,CSS 锚点定位达到 Baseline Widely Available:Chrome/Edge 125+(2024年5月)、Firefox 131+(2024年10月)、Safari 18.2+(2024年12月)。全球覆盖率超过 94%,Floating UI 能做的事浏览器自己全包了。

核心语法:先定位,再声明后备

/* 锚点元素 */
.trigger {
  anchor-name: --menu-trigger;
}

/* 浮层:先声明跟着谁、放在哪 */
.dropdown {
  position: absolute;
  position-anchor: --menu-trigger;
  position-area: bottom span-right;
  margin-top: 6px;
  /* 自动翻转后备方案 */
  position-try-fallbacks: flip-block, flip-inline, flip-block flip-inline;
}

position-try-fallbacks 里写的是浏览器尝试的顺序:先保持原位,如果下边超屏就翻到上边(flip-block),如果右边也超屏就翻到左边(flip-inline),最后还有个组合 flip-block flip-inline 处理对角线情况。

自定义后备:给箭头方向也翻一下

简单翻转只能换位置,有时候箭头方向也要跟着变。用命名 @position-try 规则:

@position-try --flip-above {
  position-area: top span-right;
  margin-top: 0;
  margin-bottom: 6px;
  --arrow-direction: down;
}

@position-try --flip-left {
  position-area: bottom span-left;
  --arrow-direction: right;
}

.dropdown {
  position-anchor: --menu-trigger;
  position-area: bottom span-right;
  margin-top: 6px;
  position-try-fallbacks: --flip-above, --flip-left;
}

命名后备比关键词灵活——可以同时换 position-area、换 margin,甚至通过 CSS 变量把箭头方向一起翻掉。这是 Floating UI 的 flip() + shift() middleware 组合的纯 CSS 等价物。

搭配 Popover API:连 JS 都不用写

锚点定位和 HTML popover 属性天然配对:

<button popovertarget="menu" popovertargetaction="toggle" class="trigger">
  Open Menu
</button>
<div popover id="menu" class="dropdown">
  <a href="#">Option 1</a>
  <a href="#">Option 2</a>
  <a href="#">Option 3</a>
</div>
.trigger { anchor-name: --menu-btn; }
#menu {
  position: absolute;
  position-anchor: --menu-btn;
  position-area: bottom span-right;
  margin-top: 4px;
  position-try-fallbacks: flip-block;
}

点击按钮toggle、弹出层定位、溢出翻转——全是浏览器原生行为,一行 JS 都没有。

性能差距是根本性的

Floating UI 的 computePosition() 在 JavaScript 微任务队列里跑,每次都要 getBoundingClientRect() 触发重排;在低配手机上滚动菜单会有可感知的延迟。CSS 锚点定位是浏览器的布局引擎自己算的,没有 JS、没有 requestAnimationFrame、没有重排。在有 100+ 个浮层同时更新的场景下,这个差距会直接变成帧率数字。

Safari 和 Firefox 的现状

Safari 18.2–18.3 支持 anchor()position-anchor,但还不支持 @position-try 后备。建议把基础位置写在 @position-try 外面作为 base,这样 Safari 用户能看到正确位置,只是没有自动翻转,需要再升到 18.4+ 才有完整行为。Firefox 131+ 已支持 position-try-fallbacks 关键词,命名 @position-try 规则在 Firefox 147+。

下一步

如果你项目里还有 npm install @floating-ui/react,今天可以打开 DevTools 试一下:把 dropdown 的定位改成 position-anchor + position-area,把 JS 翻转逻辑删掉,看看浏览器自己能不能跑起来。能跑的话,就是零成本去掉了 30KB 的运行时依赖。

评论区

0 条评论

登录后可评论。