你以为浮层定位只能靠 JS 算坐标?今天 CSS 把这件事彻底原生化了
每次写 tooltip、dropdown、popover,都要先 npm install 一个库,然后用 getBoundingClientRect() 算坐标、监听 scroll 和 resize 重新算、写一整套 flip 逻辑防止超屏。Popper.js 每周 7780 万次下载,Floating UI 每周也有几百万次。这个问题存在了十几年。今天,CSS Anchor Positioning 彻底把它原生化了。
这个问题存在了十几年
做浮层 UI 的人都知道这个痛:按钮上挂一个 tooltip,要先读按钮的坐标,加 scroll 偏移,再设 top/left。页面一滚动、窗口一 resize,整个逻辑要重跑一遍。Popper.js 解决的是这件事,但它自己也是个 npm 包——需要初始化、管理生命周期、还是在主线程跑 JavaScript。
三行 CSS 替代一整套库
CSS Anchor Positioning 核心就三个属性:
/* 按钮:声明自己是一个锚点 */
.trigger {
anchor-name: --my-tooltip;
}
/* 浮层:绑定到锚点,然后定位 */
.tooltip {
position: absolute;
position-anchor: --my-tooltip;
top: anchor(bottom); /* 浮层顶部 = 按钮底部 */
left: anchor(center); /* 浮层左边 = 按钮水平中点 */
translate: -50% 0; /* 水平居中 */
}
不需要 JS,不需要库,不需要 refs,不需要 middleware。
比库更好的性能
| CSS Anchor Positioning | Floating UI | |
|---|---|---|
| 打包体积 | 0 KB(浏览器原生) | ~12 KB |
| 计算位置 | GPU(合成器线程) | 主线程 CPU |
| 滚动/Resize 重新定位 | 浏览器自动 | 手动 observers |
| 视口越界翻转 | position-area 一行 |
flip() middleware |
Mintec 在 Q2 2026 迁移了三个项目,测量到含 30+ tooltip 的页面 INP 改善 40-80ms。一个开发者把一个 Webflow SaaS 页面的 Lighthouse 分数从 71 提到 92,只因为把 Tippy.js 和 Floating UI 换成了纯 CSS。
视口越界不用 JS 了
之前最麻烦的部分是”浮层超屏了怎么办”——Floating UI 要写一整套 flip middleware。CSS 用 position-area 或者 @position-try:
.tooltip {
position: absolute;
position-anchor: --my-tooltip;
position-area: top center; /* 优先放上面 */
position-try-fallbacks: flip-block; /* 不够位置就翻到下面 */
}
这就是 Floating UI 几十行 JS 做的事,一行 CSS 搞定。
配合 Popover API 连展示逻辑都不用 JS
HTML 的 popover 属性(Baseline 2024)处理显示/隐藏、Esc 关闭、点击外部关闭、top-layer 层级:
<button popovertarget="tip">hover me</button>
<div id="tip" popover>tooltip 内容</div>
popover 处理展示,position-anchor 处理位置,两个原生 API 组合起来,零 JS 替代整个 tooltip 库。
浏览器支持
- Chrome 125+(2024 年 5 月)
- Firefox 132+(2024 年 9 月)
- Safari 18.2+(2024 年 12 月)
- Baseline 2026,覆盖约 91% 全球流量
渐进增强写法
/* 现代浏览器:原生定位 */
@supports (anchor-name: --test) {
.tooltip {
position-anchor: --trigger;
inset-area: top center;
}
}
/* 老浏览器:静态回退位置 */
@supports not (anchor-name: --test) {
.tooltip {
top: 0;
left: 50%;
transform: translateX(-50%);
}
}
什么时候还要用 Floating UI
- 虚拟元素(锚点不在 DOM 里,比如 canvas 上跟随鼠标的 tooltip)
- 需要平滑的定位过渡动画(CSS 切换位置没有动画,Floating UI 可以做)
- 极老的浏览器用户还占相当比例的企业场景
下一步
下次写 tooltip、dropdown 或者 popover,先去 caniuse 查一下 Anchor Positioning 的支持率。如果你的用户主要是 2024 年以后的浏览器,直接写 CSS,删掉那个 npm 包。
实测步骤:
- 查 caniuse.com 查询 anchor-name 支持率
- 给 trigger 加
anchor-name: --my-anchor - 给浮层加
position-anchor: --my-anchor和position-area - 用
@supports包一层老浏览器回退 - 删 npm 包,看 Lighthouse 分数变化
评论区
登录后可评论。