你以为浮层防溢出只能靠 JS?配了五年 tooltip,今天 CSS @position-try 把它彻底原生化了
写前端的人踩过这个坑——tooltip 放不到视口边缘,一翻就出屏幕,要靠 Popper.js 算坐标、监听 resize、更新位置,一个 tooltip 写下来比业务逻辑还长。
这个坑,CSS 现在原生填上了。
声明锚点,浏览器自动算位置
用 anchor-name 给触发元素挂个名字,被定位的元素用 position-anchor 指向它:
.btn-help {
anchor-name: --help-btn;
}
.tooltip {
position: absolute;
position-anchor: --help-btn;
top: calc(anchor(bottom) + 8px);
left: anchor(center);
translate: -50% 0;
}
这行 CSS 干了以前 30 行 JS 干的事:把浮层钉在触发元素下方、水平居中。
防溢出不用 JS,靠 @position-try 声明式兜底
tooltip 在视口底部会溢出——这才是让整件事变复杂的原因。以前靠 resize observer 算空间,@position-try 把这个逻辑声明掉了:
.tooltip {
position-try-fallbacks: flip-block;
}
flip-block 是内置关键字,自动把 tooltip 翻到触发元素上方。也可以写自定义兜底:
@position-try --flip-above {
top: unset;
bottom: calc(anchor(top) + 8px);
margin-top: 0;
margin-bottom: 8px;
}
@position-try --shift-right {
left: anchor(right);
translate: none;
}
.tooltip {
position-try-fallbacks: --flip-above, --shift-right;
}
浏览器按顺序试每个兜底方案,选第一个不出界的。不用事件监听,不用定时器重算。
配合 Popover API 零 JS 搭下拉菜单
tooltip 配 Popover API,连显示/隐藏都不用 JS:
<button popovertarget="menu" popovertargetaction="toggle" id="menu-trigger">
打开菜单
</button>
<div id="menu" popover>
<button>选项一</button>
<button>选项二</button>
</div>
#menu-trigger {
anchor-name: --menu-trigger;
}
#menu {
position: absolute;
position-anchor: --menu-trigger;
inset-area: bottom span-all;
position-try-fallbacks: flip-block;
}
按钮控制显隐,浏览器处理焦点管理、轻触外部自动关闭,CSS 处理定位和溢出翻转。这是以前一整套 React 组件才能做到的事。
浏览器支持:三大引擎全部稳定,Baseline 2026
| 特性 | Chrome | Safari | Firefox |
|---|---|---|---|
| anchor-name / position-anchor | 125+ | 18+ | 131+ |
| position-try-fallbacks | 129+ | 26+ | 147+ |
| @position-try 自定义规则 | 125+ | 26+ | 147+ |
截至 2026 年 9 月,全球覆盖约 75-80%。对主流用户够了,渐进增强写法兜底:
.tooltip {
/* 不支持 anchor 的浏览器:静态定位 */
top: 100%;
left: 50%;
translate: -50% 0;
}
@supports (anchor-name: --x) {
.tooltip {
position-anchor: --trigger;
inset-area: bottom center;
position-try-fallbacks: flip-block;
}
}
下一步
如果你现在用的是 Popper.js 或 Floating UI,下周抽半天把最常用的 tooltip 组件换掉这个写法——anchor-name 加一行、position-anchor 加一行、position-try-fallbacks 加一个关键字,resize observer 和 scroll listener 整块删掉。实测下来代码量少 60%,性能还更好。
浮层定位这个坑,CSS 早就原生填上了,只是社区传导还需要时间。
评论区
登录后可评论。