CSS 与布局 / CSS Anchor Positioning · 把元素钉在另一个元素旁 / 细节与边界 待审核 7 / 7
gotchas · 细节与边界

细节与边界

主线能力见本系列其他各页。这一页收集容易出错、容易记混的细节,多数出自规范与 MDN 的边角;其中四条在 Chrome 151 上实测过,实际行为与流传的说法并不一致(核对于 2026-08)。

当前浏览器对 anchor positioning 的实测支持情况,由 CSS.supports() 探测。

1 · 锚与浮层的先后约束

本系列前几页与许多教程都说「浮层放哪都行、跨 DOM 层级都能对齐」,这一说法并不严谨。Chris Coyier 写过这条限制:浏览器布局偏向单遍完成,轮到浮层时它引用的锚需要已经布局好。规范据此把「可接受的锚元素」定义为在布局上严格先于被定位元素,落到常见写法上就是两条:

  • DOM 顺序:同一包含块内,锚要排在浮层前面。把浮层写在锚之前,anchor() 会解析不到而静默失败,不报错,只是不贴。
  • 包含块:浮层的包含块要能包住那个锚,否则同样连不上。
图 1-1 · 一对兄弟元素在两种 DOM 顺序下的锚定结果。可点按钮调换顺序,读数会实测当前浏览器是否还锚得住。

警示 · 这条限制至今没有放宽(核对于 2026-08)。规范正文仍要求锚「laid out strictly before」被定位元素;实测 Chrome 151 把浮层写在锚之前时,top: anchor(bottom); left: anchor(left) 整体失效,浮层退回未锚定的静态位置(在 400×160 的舞台里落到左上角 0, 0,而锚定成功时应落在 200, 70)。稳妥的写法是让锚与浮层做兄弟、锚放前面(锚 position: static,浮层 position: absolute),本系列画连接线页正是特意把连接线放在两个气泡之后。

2 · 一个元素上的多个 anchor-name

anchor-name 的语法很像 CSS 自定义属性,都以 -- 开头,但它不是变量,不能套 var()。一个元素可以同时起多个名字,逗号分隔,于是它能被不同浮层以不同身份引用。

图 2-1 · 同一元素挂多个 anchor-name 时的声明写法与各浮层的引用方式。

3 · 隐式绑定与显式绑定

图 3-1 · 经 position-anchor 的隐式绑定与在 anchor() 里写出锚名的显式绑定的对照。

4 · 锚被隐藏时的三种表现

「锚一隐藏,浮层就跟着没」这个说法要分情况,三种隐藏方式的效果并不一样。

图 4-1 · 锚分别被 display: nonevisibility: hiddencontent-visibility: hidden 处理后浮层的反应。可逐项施加观察差异。

注 · Chrome 151 实测(核对于 2026-08):锚 display: nonecontent-visibility: hidden 时不再生成盒子,anchor() 失效,浮层不是消失而是退回未锚定的位置;锚在 content-visibility: hidden 的祖先子树里同样失效。锚 visibility: hidden 时仍占布局,浮层照常贴着它,看不见的锚也能当锚。若希望锚消失时浮层一起隐藏,应显式声明联动:用 position-visibility: anchors-visible(见溢出回退页 §4),或给 anchor() 加 fallback 值,让它在锚失效时退回指定位置。

5 · inset 与 position-area 的并存

浮层上既写了 top / left,又写了 position-area 时,两者不是互相覆盖的关系。position-area 把选中的那一格设为浮层新的包含块,inset 属性随后在这个新包含块内生效:取 auto 的 inset 按 0 处理,写了具体值的则是从 position-area 的对应边起算的偏移。

图 5-1 · 一个挂着 top: 8px; left: 8px 的浮层在 position-area 生效前后的落点。可勾选切换,对照两处坐标。

警示 · 常见的说法是「同时存在时 position-area 优先,inset 被忽略」,实测不成立。在 400×220 的包含块里放一个 left: 150px; top: 90px; width: 100px; height: 40px 的锚,浮层 60×20:只写 position-area: top center 时浮层落在 (170, 70),即横向在锚所在的列内居中、底边贴住锚的上边;再补上 top: 8px; left: 8px,落点变成 (158, 8)。若 inset 真被忽略应仍是 (170, 70),若 inset 压过 position-area 应是 (8, 8),两者都不是。158 是从该格左缘(即锚的左缘 150)起算的 8px 偏移,8 是从该格上缘(即包含块顶边 0)起算的 8px 偏移(Chrome 151,核对于 2026-08)。

本节也回答了另一个常见提法:「anchor positioning 改变了被定位元素的包含块」。这句话只在用了 position-area 时成立,此时包含块确实被换成选中的格子。只用 anchor() 时浮层仍在它原本的包含块里布局(absolute 看最近的定位祖先,fixed 看视口),anchor() 只是把锚的几何作为计算 inset 的参照。浮层在 DOM 与包含块里的位置,和它看起来贴着谁,始终是两件事。

6 · anchor() 与 anchor-size() 的适用范围

anchor() 返回锚某条边的位置,只能用在 inset 属性里。anchor-size() 返回锚的尺寸,可用在尺寸属性、inset 属性与 margin 属性上,适用面更广。

图 6-1 · 两个函数各自可用的属性与维度关键字。

警示 · 两处流传的说法需要更正。其一,anchor-size() 并非「不要求定位」:MDN 明确要求元素 positionabsolutefixed 且已关联到锚,否则取 fallback,无 fallback 则丢弃该声明;实测在 position: static 元素上写 width: anchor-size(width),宽度仍按 auto 撑满包含块(400px),而同样写法的绝对定位元素得到锚宽 100px。其二,浮层未显式设尺寸时并非「按 max-content 撑开」,而是绝对定位一贯的 shrink-to-fit:在 400px 宽的包含块里 left: 10px,短内容量得 13px,长内容被可用宽度截到 390px 而非继续外溢(Chrome 151,核对于 2026-08)。内容窄于可用宽度时 shrink-to-fit 恰好等于 max-content,MDN 示例给人的印象出自这种巧合。

7 · position-area 取值速查

  • 单关键字简写:top 等价于 top span-all,即贴上边并横向铺满;center 等价于 center center,覆在锚上。
  • 两关键字:topleft / center / rightbottom 同理;left / rightcenter / span-top / span-bottom
  • span-* 指的是向哪个方向横跨,结果常与直觉相反:top span-left 向左铺,浮层因而右对齐到锚;top span-right 向右铺,浮层左对齐;span-all 沿该轴铺满。
  • 逻辑关键字随书写方向:block-start / block-end / inline-start / inline-endstart / end 分别是块轴与行内轴的 start / end;另有 span-start / span-endspan-inline-start|endspan-block-start|end
  • 物理轴:x-start / x-endy-start / y-end
  • 对齐微调:align-self / justify-self(及 place-self / place-items)取 anchor-center,可用在 absolute 与 fixed 上让浮层在锚上居中。

注 · 两处旧名。position-area 早期在 Chromium 里叫 inset-area,现已不再作为别名保留,实测 Chrome 151 的 CSS.supports('inset-area', 'top center') 返回 false(核对于 2026-08)。position-try-fallbacks 则有简写 position-try: <order> <fallbacks>,这一个仍然可用。