⚓ CSS Anchor Positioning · 把元素「钉」在另一个元素旁
tooltip、下拉菜单、popover、气泡提示——本质都是「让 B 元素贴着 A 元素的某条边出现」。长期以来这件事并不容易:要么把 B 放进 A 的 position:relative 容器里(于是被 overflow:hidden 裁掉、被 z-index 压住),要么用 JS 监听滚动 / resize 反复 getBoundingClientRect() 手算坐标。CSS Anchor Positioning 把它变成纯 CSS:给 A 起个 anchor-name,让 B 用 anchor() / position-area 引用它—— B 不必再是 A 的子孙、能待在 top layer(popover / dialog),也能精确对齐并自带溢出翻转。 (一条常被忽略的约束:为跨浏览器稳妥,应锚在前、包含块能包住锚——见 「细节与边界」页。) 阅读本系列需要先了解 position: absolute、包含块 (containing block) 与 stacking 的基础, 可参考 how-css-works 与 stacking-contexts 两个系列。
anchor-name: --x → 给浮层 position: absolute; position-anchor: --x → 用 anchor()(精确到边)或 position-area(九宫格,更简洁)摆位 → 用 position-try-fallbacks 处理「接近视口边缘时自动翻到另一边」。为什么要它:两个角色 + 跨包含块的定位
先看传统方案的局限(relative 容器被裁剪 / JS 手算坐标会抖动)。再认识 anchor positioning 的两个角色:锚元素(anchor-name)与浮层(position-anchor + 绝对定位)。动手拖动锚,观察浮层跨越 DOM 层级、无视 overflow地跟随——这是它和 position:relative 的本质区别。
anchor() 与 anchor-size():贴边对齐 & 跟随尺寸
底层主力函数。anchor(top/bottom/left/right/start/end/center/%) 用在 top/left/inset-* 里,把浮层的某条边钉到锚的某条边;anchor-size(width/height/...) 让浮层尺寸跟着锚走(下拉框宽度=输入框宽度的经典需求)。拖滑块把浮层贴到锚的任意边角,实时看生成的 CSS。
position-area:一行实现的九宫格摆位
高层简化 API:把锚周围想象成 3×3 网格,position-area: top center 就把浮层放到正上方,无需触碰 top/left。点九宫格任意格子观察浮层移动;再尝试 span-* 跨格、逻辑关键字(block-start/inline-end)、以及 justify-self: anchor-center 对齐。
溢出回退:position-try-fallbacks / @position-try
浮层接近视口边缘、首选位置放不下时,position-try-fallbacks 提供一串候选位置:内置 flip-block / flip-inline / flip-start 翻转,或用 @position-try 自定义一整套位置。再配 position-try-order 选空间最大的候选、position-visibility 在锚滚出视野时自动隐藏。把锚拖到取景框边缘,观察浮层自动翻面。
实战配方:Popover 组合、等宽下拉、anchor-scope
把 anchor() / position-area / position-try 组合成实用案例:Popover API + anchor(top-layer 浮层 + 纯 CSS 定位,无 JS 跟随)、等宽下拉(anchor-size)、一个锚挂多个浮层、列表里同名锚用 anchor-scope 隔离。最后讲渐进增强——用 @supports 为不支持的浏览器提供降级,以及当前 2026 的支持现状。
进阶用法:用 anchor() 在两个元素之间画连接线
其他各页的浮层都只锚定一个锚。这页换一种思路:让同一个元素的四条边分别 anchor() 到两个不同的锚,把它撑成「跨越 A 与 B」的盒子,只画左+下两条边 → 一根评论↔回复的 thread 连接线(灵感来自 Roland Franke 的 frontend story)。纯 CSS、随内容自适应,再用 anchor-scope 让一长列 thread 各连各的。
细节与边界:规范角落里的 fine print
主线能力之外,真正上手才会遇到的细节:一个元素挂多个 anchor-name、隐式 vs 显式绑定;实测锚被 display:none / visibility:hidden / content-visibility:hidden 时浮层各自的表现(与「常见说法」不一样);inset 与 position-area 并存时谁优先;anchor-size() 的默认尺寸与适用范围;以及 position-area 全取值速查(span-* 的反直觉对齐)。
🔗 相关链接
📐 规范 / 文档
- CSS Anchor Positioning Level 1 W3C / CSSWG 规范本体,所有属性 / 函数 / 取值的权威定义。
- MDN · CSS anchor positioning 指南 developer.mozilla.org 各属性的用法说明、示例与逐项兼容性表。
- web.dev · Learn CSS: Anchor positioning Chrome 团队 从零到进阶的官方教程,配大量可玩 demo。
- A Deep Dive Into CSS Anchor Positioning Ahmad Shadeed 图解极佳的深入长文,把 position-area / span 之类讲得很直观。
- Can I use · css-anchor-positioning caniuse.com 实时浏览器支持矩阵(以它和本页顶部横幅的实测为准)。
- OddBird anchor-positioning polyfill github.com 需要覆盖不支持的浏览器时,这个 polyfill 可作渐进增强的回退。
🎨 实例与用法(本系列灵感来源)
-
Custom range slider:anchor positioning + 滚动驱动动画
Frontend Masters
把滑块 thumb 起名
anchor-name: --thumb,让<output>气泡position-area: top跟着跑;再用 scroll-driven 的view-timeline读出实时值、anchor-scope: all隔离多个滑块。和我们的 css-animation 系列正好串起来。 -
Anchor Interpolated Morphing (AIM)
Adam Argyle
进阶用法:把 anchor 与
@starting-style+interpolate-size+transition(allow-discrete)叠加,让 popover / 对话框从触发点"生长"出来(纯 CSS、可打断,无需 View Transitions)。同样能接上 css-animation 系列。