配了三年弹层,每次被屏幕边缘截掉我都要靠JS硬算位置——今天CSS自己会”找路”了,@position-try把这件事彻底原生化了
弹层被屏幕边缘截掉这件事,我算了五年。
一个 tooltip 要出现在按钮上方,但按钮在页面底部,于是 tooltip 跑出视口了。一个下拉菜单宽度要跟输入框对齐,但输入框本身已经很宽了,于是超出的部分被截了。以前解决这些问题全靠 JavaScript:getBoundingClientRect() 拿坐标,ResizeObserver 监听变化,判断元素是否溢出然后手动调 position。代码一堆,还容易出 bug。
2026 年,CSS 自己会「找路」了。
这件事的核心变化是什么
CSS Anchor Positioning 模块在 2026 年进入了 Baseline,Chrome、Firefox、Safari 全部支持。配合 @position-try,弹层终于可以自己判断「这个位置放不下我就换一个」,而不需要 JavaScript 在每次渲染时重新算。
具体来说是这样工作的:
/* 声明锚点:一个按钮 */
.trigger-btn {
anchor-name: --my-trigger;
}
/* 弹层跟锚点绑定 */
.tooltip {
position: fixed;
position-anchor: --my-trigger;
top: anchor(bottom); /* 顶部对齐锚点底部 */
left: anchor(center); /* 左侧对齐锚点水平中心 */
transform: translateX(-50%); /* 居中偏移 */
margin-top: 8px;
}
/* 备选方案:放不下就翻到下方 */
@position-try --flip-below {
top: auto;
bottom: anchor(top);
margin-top: 0;
margin-bottom: 8px;
}
.tooltip {
position-try: --flip-below;
}
这就是 @position-try 的核心用法:当第一个位置溢出视口时,浏览器自动应用你定义的备选位置。完全不需要 JavaScript。
position-area 让你更偷懒
如果你连「顶部对齐锚点底部」这种描述都懒得写,position-area 直接给你 9 宫格级别的控制:
.tooltip {
position: fixed;
position-anchor: --my-trigger;
position-area: top; /* 默认放上方 */
position-try-fallbacks: flip-block; /* 放不下就翻到对面 */
}
position-area: top 等价于「把弹层放在锚点的上方」。flip-block 等价于「如果上方放不下,就翻到下方」。浏览器会自动在这两个选项里挑一个能完整显示的。
position-visibility: anchors-visible 解决了滚动问题
这是我之前踩了三年的坑:弹层定位在锚点上方,锚点滚出视口了,但弹层还在原地。这个行为在技术上没有错,但在用户体验上是 bug。
解决方案是一个 CSS 属性:
.tooltip {
position-visibility: anchors-visible; /* 锚点滚走了弹层也跟着滚 */
}
加了这一行,锚点被滚动出视口时,弹层会自动消失。锚点再次出现时,弹层跟着出现。不需要 JavaScript 监听 scroll 事件。
配合 Popover API 使用体验更好
@position-try 和 Popover API 是天造地设的一对:
<button popovertarget="my-tooltip" class="trigger-btn">
点我
</button>
<div popover id="my-tooltip" class="tooltip">
提示内容
</div>
.trigger-btn {
anchor-name: --tip-trigger;
}
.tooltip {
position: fixed;
position-anchor: --tip-trigger;
position-area: bottom;
position-try-fallbacks: flip-block;
position-visibility: anchors-visible;
}
popover 属性处理「显示/隐藏、焦点管理、点击外部关闭」。CSS 处理「弹层出现在哪、溢出了怎么办、锚点滚走要不要跟着消失」。分工明确,各干各的。
什么时候还需要 JavaScript
CSS Anchor Positioning 能覆盖 80% 的弹层场景。但如果你需要:
- 鼠标跟随的 Tooltip(cursor 位置是动态的,CSS 锚点无法监听鼠标)
- 虚拟元素(弹层要跟随一个不存在的 DOM 节点)
- 复杂的排他逻辑(比如多个弹层联动)
这些场景 Floating UI / Popper.js 仍然有用。但从今天开始,如果你的项目只需要「按钮上方出不来就翻到下方」这种逻辑,先试试纯 CSS。
落地方案
三步走:
第一步:确认浏览器支持。Chrome 125+、Firefox 131+、Safari 18.2+。全球覆盖率 88%,大多数项目可以直接用,不需要回退。
第二步:把现有的 Popper.js / Floating UI 弹层抽一个出来改成纯 CSS,看功能是否完整。大概率会发现 90% 的逻辑不需要 JavaScript。
第三步:新项目直接用 CSS Anchor Positioning + Popover API 开发弹层组件,不再引入定位类库的依赖。
INP 指标也会变好看:弹层定位的计算从 JavaScript 主线程移到了渲染引擎,滚动时不会再有额外的布局重算。
弹层被屏幕边缘截掉这件事,到 2026 年终于不用靠 JavaScript 硬算了。CSS 自己会找路这件事,等了五年。
评论区
登录后可评论。