写过浮层的人都踩过这个坑——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 的运行时依赖。
评论区
登录后可评论。