配了三年弹层,每次被屏幕边缘截掉我都要靠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 自己会找路这件事,等了五年。

评论区

0 条评论

登录后可评论。