锚点定位入门
摘要
一份全面的CSS锚点定位API指南,解释了如何使用 `position-anchor` 和 `position-area` 属性将元素锚定到其他元素,涵盖了如工具提示和下拉菜单等常见用例。
<p><a href="https://lobste.rs/s/znka50/getting_started_with_anchor_positioning">评论</a></p>
查看缓存全文
缓存时间: 2026/07/07 20:20
# 锚点定位入门 • Josh W. Comeau
来源:https://www.joshwcomeau.com/css/anchor-positioning/
## 简介
Web 上常见的一种 UI 模式是将一个元素附着在另一个元素上。工具提示需要浮动在其目标上方,下拉菜单需要从触发按钮下方展开。
这看起来很简单,但细节才是关键。我们可能希望工具提示浮动在目标上方,但如果目标恰好位于视口顶部,它就会溢出:
这是一个显示按钮附加信息的工具提示。
工具提示放置得很舒适。
这是一个显示按钮附加信息的工具提示。
工具提示被截断了!
过去,我们通常使用 JavaScript 来解决这类问题,而管理这些逻辑的代码可能变得相当复杂。幸运的是,一个新式的浏览器 API 替我们处理了所有难题:**Anchor Positioning API**。
我自己也还在学习这个新 API,说实话,一开始我觉得所有选项有点令人不知所措。底层的问题空间很复杂,而 Anchor Positioning API 旨在解决广泛的问题。我认为**80/20 法则**在此适用:80% 的产出来自 20% 的输入。在这个例子中,我认为约 20% 的 Anchor Positioning API 可以解决约 80% 的实际使用场景。因此,在这篇文章中,我们将介绍这个 API 最关键的几个部分,以便你今天就能开始尝试!
## 锚点与目标(跳转到此标题) (https://www.joshwcomeau.com/css/anchor-positioning/#anchors-and-targets-1)
让我们从一个基本的“Hello world”示例开始:
在使用锚点定位时,我们通常关心两个元素:
1. **锚点元素。** 这是我们要将某个元素附着上去的基础元素。
2. **目标元素。** 这是浮动元素,它应以某种方式附着到锚点元素上。
Anchor Positioning API 是**定位**布局模式的扩展;要使用它,目标元素必须设置 `position: absolute` 或 `position: fixed`。
**这真的帮我理解了这里发生了什么。** 通常在使用绝对/固定定位时,我们将元素锚定在其包含块的边缘。例如,我们可以通过设置 `top: 0; left: 0;` 将绝对定位元素粘在左上角。Anchor Positioning API 赋予了我们一个新的超能力:我们可以使用**另一个元素**作为锚点!
为此,我们需要指定**哪个**元素应被用作锚点元素。这是一个两步过程:
1. 锚点需要使用 `anchor-name` 属性赋予一个唯一的名称。
2. 目标元素需要使用 `position-anchor` 属性指定该锚点元素。
锚点名称使用“dashed-ident”类型。这意味着它们是由开发者定义的、以两个破折号开头的名称。这使得它们**看起来**像 CSS 自定义属性,但实际上并不是同一回事(例如,没有可以用 `var()` 访问的底层值)。这正在成为现代 CSS 中相当常见的模式;我们在我的近期关于滚动驱动动画的文章中也看到了类似的情况。
最后,我们需要定义目标元素相对于其锚点的**位置**。我们可以使用 `position-area` 属性来做到这一点。在之前的“Hello world”示例中,我希望我的工具提示位于按钮**上方**,因此设置了 `position-area: top`。
要理解 `position-area`,我们可以想象在目标元素的包含块中切割出一个 3×3 的网格,锚点元素位于中间单元格。通过指定一个或两个值,我们可以控制其精确位置:
```css
.target {
position: absolute;
position-anchor: --some-anchor;
position-area: top center;
}
```
我们可以通过同时指定水平和垂直值(例如 `position-area: top left`)来选择 9 个单元格中的任意一个。如果只传递一个值,目标元素将在垂直方向上跨越整个网格;例如,如果我们设置 `position-area: top`,目标元素将横跨所有三列。我们也可以通过设置 `position-area: top span-all` 来显式指定这一点。
为了让 Anchor Positioning API 工作,我们需要提供一些约束。如果我们没有指定至少一个 `position-area` 值,目标元素就不会锚定到锚点元素上,而是浮动在其默认位置。
默认情况下,目标元素将**紧贴**其锚点。遗憾的是,没有类似 `gap` 的属性,但我们可以使用 `margin` 来添加一些空间:
## 处理溢出(跳转到此标题) (https://www.joshwcomeau.com/css/anchor-positioning/#handling-overflow-2)
在我看来,Anchor Positioning API 最有用的部分在于它的动态性。
例如,看看当我们缩小视口时“Hello World”示例会发生什么:
很酷吧?我们的目标元素会自动随其容器缩放以避免溢出。只要目标元素具有灵活的大小,这就能工作;在上面的示例中,我使用了 `max-width` 而不是 `width` 来设置默认大小。
这可能看起来没什么大不了的,因为 CSS 中的大多数东西都是这样工作的,但如果你曾经尝试用 JavaScript 编写自己的工具提示逻辑,你就会知道这东西有多令人头疼。😅
**但真正的挑战在于检测何时空间不足。** 当锚点元素靠近视口顶部时,我们可能希望工具提示翻转到下方。
幸运的是,Anchor Positioning API 对此也有解决方案。看看这个:
**目前,它还不完美。** 目标元素已经翻转到锚点的下方,但小小的工具提示箭头仍然指向下方!我们稍后会处理这个问题,但首先,让我们理解这里发生了什么。
当我们滚动页面时,浏览器会持续监控我们的目标元素是否仍然整齐地包含在其容器内,或者是否溢出。当检测到溢出时,浏览器会检查我们是否通过 `position-try-fallbacks` 属性提供了任何**后备位置**。在这个例子中,我们指定了一个后备位置 `bottom`,因此浏览器会测试目标元素是否能放在那个位置。如果可以,元素就会移动到那个区域,并一直停留在那里,直到再次检测到溢出。
该属性是复数形式(“fallbacks”而不是“fallback”),因为它接受一个逗号分隔的 `position-area` 值列表。这意味着我们可以提供**多个**后备区域,在检测到溢出时进行测试,不过在实践中,我还没有遇到需要多个后备的情况。
## 使用锚定容器查询翻转箭头(跳转到此标题) (https://www.joshwcomeau.com/css/anchor-positioning/#flipped-carets-with-anchored-container-queries-3)
好了,那么我们如何修复工具提示,使其箭头始终指向锚点呢?
事实证明,这是原始 Anchor Positioning API 中一个相当大的缺陷。没有任何方法可以判断我们的目标元素是使用了首选的 `position-area`,还是切换到了后备方案。我们需要使用 JavaScript 来测试目标元素是在锚点上方还是下方,这感觉像是前进两步后退一步。
CSS 工作组在 Anchor Positioning API 的第二个版本中想出了解决这个问题的方法。不幸的是,截至 2026 年 7 月,该 API 的 Level 2 仅在 Chromium 浏览器中可用,但 Anchor Positioning API 已被纳入 **Interop 2026**(在新标签页中打开) (https://github.com/web-platform-tests/interop/blob/main/2026/README.md#css-anchor-positioning),这是所有主要浏览器供应商之间的一项协议,旨在集中开发关键目标,所以我预计到今年年底它会在其他浏览器中落地。
**解决方案是一种新型的容器查询。** 我们的锚点可以被设置为一个“锚定”容器,然后我们可以使用 `@container` 查询根据后备值应用自定义 CSS。
我花了一点时间才理解这个,但以下是我得出的结论:
为了使其工作,我需要稍微调整 DOM 结构:现在我有一个父级 `.target` 元素,它成为我们的锚定容器,以及一个子级 `.tooltip` 元素,它包含所有的外观样式。这是因为容器不能对自身做出反应,正如我在博客文章《容器查询友好介绍》中讨论的那样。
因此,我们的 `.target` 元素处理所有 Anchor Positioning 的相关设置,包括设置锚定容器。如果这个元素离开了视口,它会从 `top` 位置区域移动到 `bottom` 位置区域。子级 `.tooltip` 元素处理所有外观,包括绘制箭头的 `border-shape`,我们使用容器查询在后备位置被使用时改变边框形状。
### 使用 flip-block 关键字(跳转到此标题) (https://www.joshwcomeau.com/css/anchor-positioning/#using-the-flip-block-keyword-4)
我们可以使用特殊的 `flip-block` 关键字,而不是显式指定 `bottom` 作为后备位置区域:
```css
.target {
position: fixed;
position-anchor: --example-anchor;
position-area: top;
position-try-fallbacks: flip-block;
}
```
`flip-block` 正如其名:它在“块”轴上翻转到相反的一侧,这通常是垂直方向。如果网站使用垂直书写模式,它也可能是水平方向,但据我所知,即使在传统上是垂直书写的语言中,垂直文字在网络上也非常罕见。
有趣的是,`flip-block` 关键字也会翻转**其他**方向属性。例如,如果我们的 `.target` 元素有 `margin-bottom`,那么当使用位置后备时,该 margin 会翻转到目标元素的**顶部**。
因此,我们不需要在锚定容器查询中添加 `margin-top`,而是可以将其移到父级 `.target` 元素中:
```css
.target {
position: fixed;
position-anchor: --example-anchor;
position-area: top;
position-try-fallbacks: flip-block;
/*
当目标元素在锚点下方时,会自动切换到顶部 margin:
*/
margin-bottom: 8px;
}
```
在这个特定案例中,我们仍然需要锚定容器查询来覆盖 `border-shape`,但在许多其他情况下,这可以提供足够的控制。而且,与目前仅在 Chromium 浏览器中可用的锚定容器查询不同,`flip-block` 已在所有主流浏览器中实现!
感谢 Jake Archibald 向我告知这一点。你可以在他精彩的博客文章《The Goldilocks customizable select height》(在新标签页中打开) (https://jakearchibald.com/2026/goldilocks-select-height/) 中了解更多信息。
## 支持旧版本浏览器(跳转到此标题) (https://www.joshwcomeau.com/css/anchor-positioning/#supporting-older-browsers-5)
那么,我们如何负责任地使用这个新特性,以免破坏旧版浏览器上用户的体验呢?
一种选择是考虑使用 polyfill!Oddbird 的优秀开发者们有一个 Anchor Positioning polyfill(在新标签页中打开) (https://github.com/oddbird/css-anchor-positioning),不过它不支持“Level 2”的容器查询功能,并且还有一些**其他限制**(在新标签页中打开) (https://github.com/oddbird/css-anchor-positioning#limitations) 需要注意。
如果 polyfill 不适合你,我们总是可以使用特性查询来提供后备体验。这里有一个快速草图:
```css
.anchor {
anchor-name: --example-anchor;
}
.target {
position: fixed;
/* 后备体验:粘在视口顶部 */
top: 0;
/*
改善后的体验,使用锚点定位,但没有视觉箭头:
*/
@supports (position-area: top) {
top: revert;
position-anchor: --example-anchor;
position-area: top;
position-try-fallbacks: flip-block;
margin-bottom: 8px;
}
}
/*
理想体验,使用 Anchor Positioning Level 2。
添加顶部/底部箭头,通过容器查询翻转。
*/
@supports (container-type: anchored) {
.target {
container-type: anchored;
}
.tooltip {
padding: 16px 16px 24px 16px;
border-shape: var(--downwards-caret);
@container anchored(fallback: bottom) {
padding: 24px 16px 16px 16px;
border-shape: var(--upwards-caret);
}
}
}
```
根据你正在构建的内容,这些选项可能有效也可能无效。老实说,我认为现在仍然有很多情况更适合依赖 JavaScript 库,至少目前是这样。正如 Jake Archibald 所说(在新标签页中打开) (https://bsky.app/profile/jakearchibald.com/post/3mq2pbeml2c24),存在一些活跃的错误导致 API 的某些部分无法在所有浏览器中可靠工作。所以,如果你遇到任何问题,请不要自责。
幸运的是,浏览器供应商正在积极解决这些问题,我相信在一两年内,这将是创建锚定 UI 的最佳方式。😄
## 总结(跳转到此标题) (https://www.joshwcomeau.com/css/anchor-positioning/#wrapping-up-6)
那么,这就是对 Anchor Positioning API 的快速介绍。很酷吧?
就像我之前提到的,Anchor Positioning API 还有很多其他的附加功能。如果你想深入了解,这里有一些资源:
以及,如果你觉得这篇博客文章有用,并且想继续向我学习,我有几个自定进度的课程,深入探讨 CSS 和 Web 开发:
- CSS for JavaScript 开发者(在新标签页中打开) (https://css-for-js.dev/)
- Whimsical 动画(在新标签页中打开) (https://whimsy.joshwcomeau.com/)
### 最后更新于
2026 年 7 月 7 日
### 阅读次数
相似文章
如何使用CSS检测元素重叠
本文演示了如何使用CSS中的锚点定位和滚动驱动动画来检测元素重叠,并根据空间限制动态隐藏装饰性元素。
我们终于学会了让 div 居中,然后浏览器又加了侧边栏
一篇关于 CSS/JS 技术和小工具的博客文章,该工具在考虑浏览器侧边栏和开发者工具的情况下正确居中 div,并通过指针事件校正位置。
CSS:不可避免的坏部分
一位非Web开发者的个人博客文章讨论了CSS中不可避免的坏部分,包括布局难题、浏览器默认设置和过度使用包装器,同时强调了可处理简单任务的子集。
值得记忆的原生网页技巧
HTMLcat 是一个提供针对 HTML、CSS 和 JavaScript 的小型原生网页技巧的资源,包括示例以及浏览器支持和无障碍访问的说明。
优化图标与标签的对齐
本文介绍了在网页设计中,使用flexbox和lh单元等CSS技术来对齐图标与标签,以确保多行文本中的正确对齐。