CSS 锚点定位
CSS Anchor Positioning API 是 Web 开发领域的颠覆性改变,因为它让你能够相对于其他元素以原生方式定位元素(称为“锚点”)。此 API 简化了许多界面功能(例如菜单和子菜单、提示、选择、标签、卡片、设置对话框等)的复杂布局要求。借助内置于浏览器中的锚点定位,您将能够构建分层界面,而无需依赖第三方库,开启了一个充满创意的世界。
Chrome 125 及更高版本提供锚点定位功能。
核心概念:锚点和定位的元素
此 API 的核心是锚点和已定位元素之间的关系。锚点是使用 anchor-name
属性指定为参考点的元素。定位元素是指使用 position-anchor
属性或在其定位逻辑中明确使用 anchor-name
以相对于锚点放置的元素。
设置锚点
创建锚点非常简单。将 anchor-name 属性应用于所选元素,并为其分配唯一标识符。此唯一标识符前面必须添加双短划线,与 CSS 变量非常相似。
.anchor-button {
anchor-name: --anchor-el;
}
分配锚点名称后,.anchor-button
将充当锚点,随时可引导其他元素的放置。您可以通过以下两种方式之一将此锚点连接到其他元素:
隐式锚点
将锚点连接到另一个元素的第一种方法是使用隐式锚点,如以下代码示例所示。position-anchor
属性会添加到要连接到锚点的元素中,并以锚点名称(在本例中为 --anchor-el
)作为值。
.positioned-notice {
position-anchor: --anchor-el;
}
通过隐式锚点关系,您可以使用 anchor()
函数定位元素,而无需在其第一个参数处明确指定锚点名称。
.positioned-notice {
position-anchor: --anchor-el;
top: anchor(bottom);
}
显式锚点
或者,您也可以直接在锚点函数中使用锚点名称(例如 top: anchor(--anchor-el bottom
)。这称为显式锚点,如果您想要锚定到多个元素,这会非常方便(如需查看示例,请参阅下文)。
.positioned-notice {
top: anchor(--anchor-el bottom);
}
相对于锚点定位元素的位置
锚点定位基于 CSS 绝对定位。如需使用定位值,您需要为定位的元素添加 position: absolute
。然后,使用 anchor()
函数应用定位值。例如,如需将锚定元素放置在锚定元素的左上角,请使用以下定位:
.positioned-notice {
position-anchor: --anchor-el;
/* absolutely position the positioned element */
position: absolute;
/* position the right of the positioned element at the right edge of the anchor */
right: anchor(right);
/* position the bottom of the positioned element at the top edge of the anchor */
bottom: anchor(top);
}
现在,您已将一个元素锚定到另一个元素,如下所示:
如需对这些值使用逻辑定位,等效项如下所示:
top
=inset-block-start
left
=inset-inline-start
bottom
=inset-block-end
right
=inset-inline-end
使用 anchor-center
将已定位的元素居中
为了更轻松地将锚定位置元素相对于其锚点居中,我们提供一个名为 anchor-center
的新值,该值可与 justify-self
、align-self
、justify-items
和 align-items
属性结合使用。
以下示例对前一个元素进行了修改,方法是使用 justify-self: anchor-center
将定位的元素置于其锚点上方居中。
.positioned-notice {
position: absolute;
/* Anchor reference */
position-anchor: --anchor-el;
/* Position bottom of positioned elem at top of anchor */
bottom: anchor(top);
/* Center justification to the anchor */
justify-self: anchor-center;
}
演示使用 justify-center
居中的锚点。
多个锚点
元素可以绑定至多个锚点。这意味着您可能需要设置相对于多个锚点的位置值。为此,请使用 anchor()
函数,并在第一个参数中明确说明您要引用的锚点。在以下示例中,已定位元素的左上角固定在一个锚点的右下角,已定位元素的右下角固定在第二个锚点的左上角:
.anchored {
position: absolute;
top: anchor(--one bottom);
left: anchor(--one right);
right: anchor(--two left);
bottom: anchor(--two top);
}
显示多个锚点的演示。
inset-area
的位置
除了来自绝对定位的默认方向定位之外,锚定 API 中还包含一个名为“边衬区”的新布局机制。
内嵌区域可让您轻松地相对于锚定元素相对于其各自的锚点放置已定位的元素,并适用于 9 单元格网格,锚定元素位于中心位置。
各种可能的边衬区定位选项,显示在 9 个网格的网格上
如需使用边衬区(而非绝对定位),请使用 inset-area
属性以及物理值或逻辑值。例如:
- 顶部居中:
inset-area: top
或inset-area: block-start
- 左居中:
inset-area: left
或inset-area: inline-start
- 底部中间:
inset-area: bottom
或inset-area: block-end
- 右居中:
inset-area: right
或inset-area: inline-end
显示多个锚点的演示。
使用 anchor-size()
设置元素大小
anchor-size()
函数也是 Anchor 定位 API 的一部分,可用于根据锚点的大小(宽度、高度或内嵌和块大小)调整已定位锚点元素的大小或位置。
以下 CSS 示例展示了如何使用此参数设置高度,即使用 calc()
函数中的 anchor-size(height)
将提示的最大高度设置为锚点高度的两倍。
.positioned-notice {
position-anchor: --question-mark;
/* set max height of the tooltip to 2x height of the anchor */
max-height: calc(anchor-size(height) * 2);
}
anchor-size
的演示
将锚点与弹出式窗口和对话框等顶层元素结合使用
锚点定位对于 popover
等顶层元素的效果非常好。和<dialog>
。虽然这些元素与 DOM 子树的其余部分放置在不同的层中,但通过锚点定位,您可以将它们绑定回,并与不在顶层的元素一起滚动。这对于分层接口来说是一个巨大的胜利。
在以下示例中,使用按钮触发了一组提示弹出式窗口。按钮是锚点,提示是已定位的元素。您可以为定位的元素设置样式,就像设置任何其他锚定元素的样式一样。在此具体示例中,anchor-name
和 position-anchor
是按钮和提示上的内嵌样式。由于每个锚点都需要唯一的锚点名称,因此在生成动态内容时,内嵌是最简单的方法。
通过 popover
使用锚点进行演示
注意 :弹出式窗口和对话框元素的用户代理样式默认处于视口的中心位置。因此,您可能会遇到布局问题。对于所有锚定位置元素,我建议您使用 inset: auto
重置这些样式,以免混淆。该样式将来可能会更改为默认的用户代理样式。
使用 @position-try
调整锚点位置
获得初始锚点位置后,您可以在锚点到达其所在块的边缘时调整位置。如需创建备用锚点位置,您可以使用 @position-try
指令和 position-try-options
属性。
在以下示例中,菜单右侧会显示一个子菜单。菜单和子菜单有效地利用了 Anchor 定位 API 与弹出式窗口属性,因为这些菜单往往锚定在触发器按钮上。
对于此子菜单,如果水平空间不足,您可以改为将其移至菜单下方。为此,请先设置初始位置:
#submenu {
position: absolute;
position-anchor: --submenu;
/* initial position */
margin-left: var(--padding);
inset-area: right span-bottom;
}
然后,使用 @position-try
设置后备锚定位置:
/* alternate position */
@position-try --bottom {
margin: var(--padding) 0 0 var(--padding);
inset-area: bottom;
}
最后,使用 position-try-options
将这两者连接起来。总体而言,它如下所示:
#submenu {
position: absolute;
position-anchor: --submenu;
/* initial position */
margin-left: var(--padding);
inset-area: right span-bottom;
*/ connect with position-try options */
position-try-options: --bottom;
}
/* alternate position */
@position-try --bottom {
margin: var(--padding) 0 0 var(--padding);
inset-area: bottom;
}
注意 :目前,如果您使用定位值应用样式,则可以为 position-try-options
添加动画效果,这些值可通过 transition
属性进行转换,如此处的演示所示。inset-area
尚无法转换,但 Chrome 团队正在寻找解决方案。
锚定位置自动翻转关键字
如果您有基本的调整,例如从上到下翻转或从左到右翻转(或两者兼有),您甚至可以跳过创建自定义 @position-try
声明的步骤,使用浏览器支持的内置翻转关键字,如 flip-block
和 flip-inline
。以下这些库用作自定义 @position-try
声明的替代项,可以相互组合使用:
position-try-options: flip-block, flip-inline, flip-block flip-inline;
翻转关键字可以显著简化您的锚标记。只需几行代码,您就可以创建一个具有替代位置且功能齐全的锚点:
#my-tooltip {
position-anchor: --question-mark;
inset-area: top;
position-try-options: flip-block;
}
通过 position-try-options: flip-block
使用自动翻转功能
position-visibility
,适用于子滚动条中的锚定广告
在某些情况下,您可能需要将某个元素锚定在网页的子滚动条内。在这些情况下,您可以使用 position-visibility
控制锚点的可见性。锚点何时显示在视野中?什么时候会消失?通过此功能,您可以控制这些选项。如果您希望定位的元素一直可见,直到锚点不在视图中,可以使用 position-visibility: anchors-visible
:
#tooltip {
position: fixed;
position-anchor: --anchor-top-anchor;
position-visibility: anchors-visible;
bottom: anchor(top);
}
position-visibility: anchors-visible
演示
或者,使用 position-visibility: no-overflow
防止锚点溢出其容器。
#tooltip {
position: absolute;
position-anchor: --anchor-top-anchor;
position-visibility: no-overflow;
bottom: anchor(top);
}
position-visibility: no-overflow
演示
特征检测和 polyfill
由于目前支持的浏览器有限,因此您在使用此 API 时可能要注意一些预防措施。首先,您可以使用 @supports
功能查询直接在 CSS 中查看支持情况。方法是用以下代码封装锚点样式:
@supports (anchor-name: --myanchor) {
/* Anchor styles here */
}
此外,您还可以使用 CSS 锚点定位 polyfill by Oddbird 对锚点定位功能执行 polyfill 操作,此功能适用于 Firefox 54、Chrome 51、Edge 79 和 Safari 10。此 polyfill 支持大多数基本锚点位置功能,但当前的实现尚不完整,且包含一些过时的语法。您可以使用 unpkg 链接,或将其直接导入软件包管理器中。
无障碍功能注意事项
虽然锚点定位 API 允许相对于其他元素定位元素,但其本身并不会在元素之间创建任何有意义的语义关系。如果锚点元素和定位元素之间确实存在语义关系(例如,定位的元素是关于定位文字的边栏注释),则可以采用 aria-details
从锚点元素指向定位的元素。屏幕阅读器软件仍在学习如何处理 aria 详情,但支持能力在不断改善。
<div class="anchor" aria-details="sidebar-comment">Main content</div>
<div class="positioned" id="sidebar-comment">Sidebar content</div>
.anchor {
anchor-name: --anchor;
}
.positioned {
position: fixed;
position-anchor: --anchor;
}
如果您使用 popover
属性或 <dialog>
元素使用锚点定位,浏览器将处理焦点导航校正,以实现适当的无障碍功能,因此您无需按照 DOM 顺序设置弹出式窗口或对话框。详细了解规范中关于无障碍功能的注意事项。
总结
这是一项全新的功能,我们期待看到您使用它构建的成果。到目前为止,我们已经看到来自社区的一些非常棒的应用场景,例如图表中的动态标签、连接线、脚注和视觉交叉引用。在您试用锚点定位时,我们非常期待收到您的反馈,如果您发现任何错误,请告诉我们。