1. 引言
CSS 绝对定位允许作者将盒子放置在页面的任意位置, 而无需考虑除其包含块之外其他盒子的布局。 这种灵活性非常有用,但也很有限——很多时候你希望相对于某个其它盒子进行定位。锚点定位 (通过position-anchor和position-area属性 以及/或锚点函数 anchor() 和 anchor-size()) 允许作者实现这一点, 即将绝对定位的盒子“锚定”到页面上的一个或多个其他盒子 (其锚点引用), 同时还允许尝试多个可能的位置, 以找到可以避免重叠/溢出的“最佳”位置。
.anchor{ anchor-name : --tooltip; } .tooltip{ /* Fixpos 表示我们无需担心包含块关系; 工具提示可以存在于DOM的任何地方。 */ position: fixed; /* 所有锚定行为都将默认为引用 --tooltip 锚点。 */ position-anchor: --tooltip; /* 将工具提示的底部对齐到锚点的顶部; 同时默认为水平居中对齐工具提示与锚点(在水平书写模式下)。 */ position-area: block-start; /* 若工具提示溢出窗口则自动切换, 使工具提示顶部对齐到锚点底部。 */ position-try: flip-block; /* 防止工具提示过宽 */ max-inline-size:20 em ; }
1.1. 值定义
本规范遵循CSS属性定义约定, 并采用[CSS2]中的值定义语法, 参考[CSS-VALUES-3]。 未在本规范中定义的值类型将在 CSS 值与单位 [CSS-VALUES-3]中定义。 与其他CSS模块组合可能会扩展这些值类型的定义。
除了各属性定义中列出的特定属性值外, 本规范定义的所有属性也接受CSS全局关键字作为属性值。 为了易读性未显式重复列出。
与CSS中大多数选择器匹配之外的操作类似, 本规范中的特性作用于扁平化元素树。
2. 锚点的确定
2.1. 创建锚点:anchor-name 属性
名称: | anchor-name |
---|---|
值: | none | <dashed-ident># |
初始值: | none |
适用于: | 所有生成principal box的元素 |
是否继承: | no |
百分比: | n/a |
计算值: | 按指定 |
规范顺序: | 按语法 |
动画类型: | 离散型 |
anchor-name 属性声明 元素是一个锚点元素, 其principal box是一个锚点盒, 并为其指定可被引用的一组锚点名称。 值定义如下:
- none
-
该属性无任何效果。
- <dashed-ident>#
-
如果元素生成了principal box, 则该元素为锚点元素, 并包含一组指定的锚点名称。 每个 锚点名称 都是树作用域名。
否则,该属性无任何效果。
锚点名称不需要唯一。 并不是所有元素都能成为 某个盒子的目标锚点元素。 因此如果使用范围合适,名称可以在多个地方复用。
注意: 如果多个元素共享同一个锚点名称且都对某个定位盒可见, 目标锚点元素将是 DOM 顺序最后的那个。 可以使用 anchor-scope 属性进一步限制对某个引用盒可见的名称。
锚点名称默认不受包裹性的作用域限制; 即使某个元素具有样式或布局包裹(或类似包裹), 其子元素的锚点名称对页面其他元素依然可见。
注意: 当一个元素位于另一个元素的跳过内容区域 (比如由于content-visibility: hidden), 它不会是一个可用锚点元素, 实际效果等同于没有名称。
2.1.1. 隐式锚点元素
某些规范可以定义,在特定情况下, 某个元素是另一个元素的隐式锚点元素。
TODO: 待补充新弹窗相关示例 (等HTML规范正式发布后)。
隐式锚点元素可以通过 auto 关键字在position-anchor中引用, 或在锚点函数中省略锚点引用进行引用。
2.1.2. 锚点的位置
本规范的若干特性会引用锚点盒的位置和尺寸。 锚点盒的位置和尺寸在布局后确定, 并且在这些场景下会包含position相关的调整 (如 position: relative 或 position: sticky)。
布局后的效果(如transform) 不会影响锚点盒的位置。
注意: 允许锚点选择是否包含 transform 或类似属性的影响 未来可能会被允许。
2.2. 锚点名称作用域:anchor-scope 属性
名称: | anchor-scope |
---|---|
值: | none | all | <dashed-ident># |
初始值: | none |
适用于: | 所有元素 |
是否继承: | no |
百分比: | n/a |
计算值: | 按指定 |
规范顺序: | 按语法 |
动画类型: | 离散型 |
该属性将指定的锚点名称以及对这些锚点名称的查找, 限定在此元素的子树范围内。 详见§ 2 锚点的确定。
各值含义如下:
- none
- 锚点名称作用域无变化。
- all
-
指定该元素及其后代定义的所有锚点名称(未被后代通过anchor-scope限定作用域的),仅对该元素的后代可见;
并限制后代仅能匹配本子树内的锚点名称至锚点元素。
该值仅影响同一树作用域下的锚点名称, 就像它是一个树作用域名一样。 (即 anchor-scope: all 和 anchor-scope: --foo, --bar, ... 列出所有相关锚点名称时效果一致。)
- <dashed-ident>
-
指定该元素及其后代定义的匹配锚点名称(未被后代通过anchor-scope限定作用域),仅对该元素的后代可见;
并限制后代仅能匹配这些锚点名称至本子树内的锚点元素。
<dashed-ident> 是一个树作用域名。
注意: 根据 [css-scoping-1], 当比较两个树作用域名时, 只有它们来自同一树时才匹配。
该属性对隐式锚点元素无效。
li{ anchor-name : --list-item; anchor-scope : --list-item; } li .positioned{ position : absolute; position-anchor : --list-item; position-area : inline-start; }
如果没有 anchor-scope,
所有
li
元素都会对所有定位元素可见,
所以它们都会相对于最后一个
li
进行定位,最终堆叠在一起。
2.3. 查找锚点
本规范中的若干内容 会根据一个锚点说明符 查找目标锚点元素, 该说明符可以是一个<dashed-ident>(也是一个树作用域引用), 应匹配页面其他地方的anchor-name属性值, 或关键字auto, 或不指定(说明符缺失)。
注意: 这些条件所体现的一般规则是, 一个元素只有在自身盒已完全布局于欲引用它的定位盒之前, 才能作为该定位盒的目标锚点元素。 CSS 的布局规则对此提供了一些有用的保证, 具体取决于锚点与定位盒之间及其包含块的关系。 下列条件列表 就是将堆叠上下文规则 精确转述为本用途相关的内容, 可确保锚点定位没有循环依赖的可能。
-
如果未传递anchor spec, 则返回默认锚点元素(如存在),否则返回空。
-
如果anchor spec为auto:
注意: 未来的API也可能定义隐式锚点元素。 届时会在该算法中显式处理,以确保协调。
-
否则,anchor spec为<dashed-ident>。 返回树顺序中最后一个满足如下条件的元素el:
-
el对query el来说是可用锚点元素。
如果没有元素满足上述条件,则返回空。
注意: anchor-scope可以限制某些锚点名称的可见性, 从而影响哪些元素可以作为某次查找的锚点元素。
注意: 不同anchor-name样式在不同影子树下不会被其它锚点函数样式看到, 保证封装性。 但不同影子树下的元素仍可以相互锚定, 只要anchor-name和 锚点函数来自同一树的样式, 比如使用::part()对影子内部元素进行样式设置。 (隐式锚点元素也不一定受限于单一树, 但具体细节取决于分配它们的API。)
-
possible anchor对positioned el来说在作用域内, 依据positioned el或其祖先上的anchor-scope的影响。
-
possible anchor在布局顺序上严格早于positioned el, 即下列任一条件成立:
-
positioned el比possible anchor处于更高的顶层
-
两者都在同一顶层但拥有不同的包含块, 且positioned el的包含块是possible anchor的包含块在包含块链中的祖先, 即下列任一:
-
positioned el的包含块为视口, possible anchor的包含块不是视口。
-
positioned el的包含块为初始包含块, possible anchor的包含块由元素生成, 且在possible anchor的包含块链中, 到达初始包含块前的最后一个包含块 要么不是绝对定位元素, 要么在树顺序上早于positioned el。
-
两者的包含块均由元素生成, 且positioned el的包含块 是possible anchor的包含块在扁平树中的祖先, 且在possible anchor的包含块链中, 到达positioned el的包含块前的最后一个包含块 要么不是绝对定位元素, 要么在树顺序上早于positioned el。
-
-
两者都在同一顶层且拥有相同的包含块, 且都为绝对定位元素, 且possible anchor在扁平树顺序上早于positioned el。
-
-
如果possible anchor处于其他元素的跳过内容, 则positioned el也处于该元素的跳过内容中。
注意: 换句话说,positioned el可以锚定到possible anchor,如果它们都在同一个跳过“叶节点”里, 但不能跨叶锚定。 这意味着跳过一个同时包含二者的元素不会导致positioned el转向其它锚点, 但仍然能防止页面其它定位元素锚定到被跳过的元素。
2.4. 默认锚点:position-anchor 属性
名称: | position-anchor |
---|---|
值: | auto | <anchor-name> |
初始值: | auto |
适用于: | 绝对定位盒 |
是否继承: | no |
百分比: | n/a |
计算值: | 按指定 |
规范顺序: | 按语法 |
动画类型: | 离散型 |
position-anchor 属性指定默认锚点元素, 它被 position-area、 position-try, 以及(默认情况下)应用于该元素的所有锚点函数所使用。 position-anchor 是 仅重置子属性, 属于 position 属性的一部分。
- auto
- <anchor-name>
-
由指定的目标锚点元素(选中的<anchor-name>)作为该盒的默认锚点元素。
默认锚点元素的principal box 即该盒的默认锚点盒。
.anchored{ position : absolute; top : calc ( .5 em +anchor ( outside)); /* 未指定锚点名称, 将自动引用默认锚点盒。 */ } .foo.anchored{ position-anchor : --foo; } .bar.anchored{ position-anchor : --bar; }
2.5. 锚点相关性
在判断元素 el 是否对用户相关时, 如果 el 的某个后代是一个目标锚点元素,用于某个定位盒 (该定位盒本身没有被跳过,且其包含块不是 el 或其后代), 那么 el 必须被视为对用户相关。
注意: 这意味着例如, 在一个content-visibility: auto 子树中的锚点, 只要有定位盒依赖它且该定位盒未被跳过, 就会阻止其子树跳过内容。 (除非锚点和定位盒都在同一个 content-visibility: auto 元素下; 它们不能循环地让彼此保持可见。)
3. 基于锚点的定位
position-area 属性提供了一种基于网格的便捷定位方式, 可以相对于默认锚点盒定位; 若需要更复杂或相对于多个盒子的定位, 可以在内边距属性中使用 anchor() 函数,显式引用某个锚点盒的边。
3.1. position-area 属性
名称: | position-area |
---|---|
值: | none | <position-area> |
初始值: | none |
适用于: | 具有默认锚点盒的定位盒 |
是否继承: | no |
百分比: | n/a |
计算值: | 关键字none或一对关键字,详见 § 3.1.3 <position-area> 的计算值与序列化 |
规范顺序: | 按语法 |
动画类型: | 待定 |
锚点定位的多数常见用例只关注定位盒的包含块边缘和默认锚点盒的边缘。 可以把这些线看作定义了一个3×3网格;position-area让你可以方便地指定 将定位盒布局在该position-area 网格的哪个区域。

- none
-
该属性无效果。
- <position-area>
-
否则,选择position-area 网格的一个区域, 并将其作为该盒的包含块。
注意: 这意味着内边距属性定义的是相对于 position-area 的偏移, 某些属性值, 如 max-height: 100%, 也会相对于 position-area。
除了none以外的值还有如下附加效果:
3.1.1. 解析定位区域网格
定位区域网格 是一个3×3网格, 每个轴由四条网格线组成。 顺序如下(使用包含块的书写模式):
注意: 当默认锚点盒部分或全部在修改前包含块之外时, 定位区域网格的某些行或列可能为零尺寸。
3.1.2. <position-area>值的语法
位置由一对值指定, 可用流向相关或物理术语表达。 <position-area>值的允许语法为:
<position-area> = [ [ left | center | right | span-left | span-right | x-start | x-end | span-x-start | span-x-end | x-self-start | x-self-end | span-x-self-start | span-x-self-end | span-all ] || [ top | center | bottom | span-top | span-bottom | y-start | y-end | span-y-start | span-y-end | y-self-start | y-self-end | span-y-self-start | span-y-self-end | span-all ] | [ block-start | center | block-end | span-block-start | span-block-end | span-all ] || [ inline-start | center | inline-end | span-inline-start | span-inline-end | span-all ] | [ self-block-start | center | self-block-end | span-self-block-start | span-self-block-end | span-all ] || [ self-inline-start | center | self-inline-end | span-self-inline-start | span-self-inline-end | span-all ] | [ start | center | end | span-start | span-end | span-all ]{1,2} | [ self-start | center | self-end | span-self-start | span-self-end | span-all ]{1,2} ]
<position-area>值通过如下方式指定所占的行和列,来选择定位区域网格的区域:
- start, end, self-start, self-end
- top, bottom, left, right
- y-start, y-end, y-self-start, y-self-end
- x-start, x-end, x-self-start, x-self-end
- block-start, block-end, self-block-start, self-block-end
- inline-start, inline-end, self-inline-start, self-inline-end
- center
- top, bottom, left, right
-
对应的单行或单列, 取决于该关键字指定的是哪个轴。
如anchor()函数, 纯逻辑关键字 (start、end等) 指的是盒子的包含块的书写模式。 x-start等则按照指定的物理轴确定方向。
self-*逻辑关键字 (self-start、x-self-end等) 与前者一致, 但指盒子自身的书写模式。
- span-start, span-end, span-self-start, span-self-end
- span-top, span-bottom
- span-y-start, span-y-end, span-y-self-start, span-y-self-end
- span-x-start, span-x-end, span-x-self-start, span-x-self-end
- span-block-start, span-block-end, span-self-block-start, span-self-block-end
- span-inline-start, span-inline-end, span-self-inline-start, span-self-inline-end
- span-top, span-bottom
-
两个相邻的行或列, 取决于该关键字指定的是哪个轴: 包含中心行/列, 以及与此关键字另一半对应的行/列(参照单轨关键字)。
(例如,span-top跨越前两行——中心行和顶部行。)
- span-all
-
三行或三列全部, 取决于该关键字指定的是哪个轴。
某些关键字在指代轴向时存在歧义:center、span-all, 以及未明确指定块或内联轴的start等关键字。 如果另一个关键字对其轴向没有歧义, 则含糊关键字指代相反轴向。 (例如,block-start center中的center指代内联轴。) 如果两个关键字都含糊, 第一个指盒子的包含块的块轴, 第二个指内联轴。 (例如,span-all start等价于span-all inline-start。)
若只提供一个关键字, 如果该关键字对其轴向没有歧义,则其行为等同于第二个关键字为span-all; 否则,行为等同于该关键字重复一次。 (例如,top等价于top span-all, 而center等价于center center。)
3.1.3. <position-area> 的计算值与序列化
计算值是<position-area>值中指示每个轴所选轨道的两个关键字, 长逻辑关键字(如 block-start)与短逻辑关键字(如 start)视为等价。 序列化时按语法顺序(见上文),逻辑关键字以短形式序列化 (例如 start start 而不是 block-start inline-start)。
3.1.4. 区域默认对齐方式
每个<position-area>也隐含一个默认自对齐方式, 当盒子的自对齐属性为normal时会被采用:
-
如果某轴只选中了中心轨道, 该轴的默认对齐方式为center。
-
如果三条轨道都被选中, 该轴的默认对齐方式为anchor-center。
-
否则,默认对齐方式为未指定的侧轨道: 如果指定的是该轴的“start”轨道, 默认对齐方式为end;依此类推。
此行为提高了定位盒子可见性和在预期范围内的可能性, 即使其包含块最终比预期小。
例如,position-area: bottom span-right值 可让定位盒从锚点的左边到包含块的右边拉伸, 并默认左对齐。 但如果定位盒比该空间还大 (如锚点非常靠近屏幕右侧), 它会向左移动以保持可见。
3.2. 锚点居中:anchor-center 对齐值
名称: | justify-self, align-self, justify-items, align-items |
---|---|
新值: | anchor-center |
自对齐属性允许绝对定位盒在内边距修饰包含块内对齐自身。 现有值结合精心选择的内边距属性, 通常已足够实现常见对齐需求, 但对于锚点定位中的常见场景——居中于锚点盒——往往需要复杂的设置。
新anchor-center值 让此场景极其简单: 如果定位盒拥有默认锚点盒, 则会在相关轴上(尽可能)居中于默认锚点盒。
若盒子不是绝对定位, 或没有默认锚点盒, 则该值行为如center,对内边距属性无额外影响。
注意: 使用anchor-center时,默认情况下 如果锚点太靠近盒子的原始包含块边缘, 会“移动”以保持在原始包含块内, 详见 CSS Box Alignment 3 § 4.4 溢出对齐:安全与不安全关键字及滚动安全限制。
3.3. 锚点相对内边距:anchor() 函数
绝对定位盒可以在其内边距属性中使用anchor()函数, 用来引用一个或多个锚点盒的位置。 anchor()函数会解析为<length>。 只能用于内边距属性(其他地方无效)。
名称: | top, left, right, bottom |
---|---|
新增值: | <anchor()> |
<anchor()> = anchor( <anchor-name>? && <anchor-side>, <length-percentage>? ) <anchor-name> = <dashed-ident> <anchor-side> = inside | outside | top | left | right | bottom | start | end | self-start | self-end | <percentage> | center
anchor()函数有三个参数:
-
<anchor-name>值 指定如何查找用于定位信息的锚点元素。可能的值有:
- <dashed-ident>
- 省略
-
选择盒子定义的默认锚点元素(如可能)。
详见目标锚点元素。
-
<anchor-side>值 用于引用目标锚点元素对应边的位置。可能的值有:
- inside
- outside
-
根据函数用于哪个内边距属性,解析为锚点盒的某一边。inside指与内边距属性相同的边(即定位盒与锚点盒“内侧”对齐), outside则是相反方向。
- top
- right
- bottom
- left
- right
-
引用锚点盒的指定边。
注意: 这些值只能用于匹配轴的内边距属性。 例如,left 只能用于 left、right, 或指向水平轴的逻辑内边距属性。
- start
- end
- self-start
- self-end
- end
-
引用锚点盒在与函数用于的内边距属性同轴上的某一边, 关键字根据定位盒的书写模式 (对于 self-start 和 self-end), 或定位盒的包含块 (对于 start 和 end)解析。
- <percentage>
- center
-
引用start与end两侧之间对应百分比的位置, 0%等价于start,100%等价于end。
center等价于50%。
- inside
-
可选的<length-percentage>最后参数为回退值, 指定当函数为不可解析锚点函数时应取的值。
anchor()函数表示可解析锚点函数时,会在计算值阶段 (使用样式与布局交错), 解析为使定位盒的内边距修饰包含块边缘 与目标锚点元素指定边界线对齐的<length>, 假定所有滚动容器在目标锚点元素与定位盒的包含块之间都处于初始滚动位置 (详见 § 3.4 考虑滚动)。
注意: 这意味着使用transition或动画的属性,只要用到锚点函数,各种变化都能“按预期”工作: 锚点盒移动、锚点元素被添加或移除、 anchor-name属性变化等。
如果目标锚点元素为分片, 则使用分片的边框盒的轴对齐包围矩形。
.bar
元素的 block-start 边
与 --foo 锚点的 block-start 边对齐的长度。
另一方面,
.bar { inset-block-end: anchor(--foo block-start); } 中,
会解析为使 .bar
元素的 block-end 边
与 --foo 锚点的 block-start 边对齐的长度。
由于inset-block-start 和 inset-block-end值分别指定从元素包含块的 block-start 和 block-end 边的内边距, 同一个anchor()通常在每个属性中解析为不同的长度。
例如,以下代码会让元素的内边距修饰包含块在锚点盒上居中,并且最大宽度不会溢出包含块:
.centered-message{ position : fixed; max-width : max-content; justify-self : center; --center : anchor ( --x50 % ); --half-distance : min ( abs ( 0 % -var ( --center)), abs ( 100 % -var ( --center)) ); left : calc ( var ( --center) -var ( --half-distance)); right : calc ( var ( --center) -var ( --half-distance)); bottom : anchor ( --x top); }
这对于一个错误信息,
比如用于
input
元素时,
是比较合适的,
因为居中会更容易让用户发现对应的输入框。
3.3.1. anchor() 的解析
只有以下所有条件均成立时,anchor() 函数才是一个可解析锚点函数:
-
应用于绝对定位盒。
-
如果 <anchor-side> 使用的是物理关键字, 那么它需要在适用于该轴的内边距属性中指定。 (例如,left只能用于 left、right 或指向水平轴的逻辑 内边距属性。)
-
对于使用该函数的盒子,存在一个目标锚点元素,且函数中指定了 <anchor-name> 值。
如果以上任一条件不成立, anchor() 函数会取其回退值作为计算值。 如果未指定回退值, 则引用它的声明在计算值阶段无效。
3.4. 考虑滚动
出于性能考虑, 实现通常会在单独的滚动/合成线程上执行滚动, 该线程能力有限 (仅支持简单的移动、变换等,无布局等高耗操作), 因此可以保证对滚动的响应足够快,被认为是“瞬时”的。
如果滚动只会让锚点定位元素移动, 理论上没有问题; 移动可以在滚动线程上完成, 定位元素会随滚动内容平滑移动。 但锚点定位允许元素 让自身相对边缘的位置依赖于不同滚动上下文中的内容, 这意味着滚动可能只会移动某一个边缘并导致尺寸变化, 从而触发布局。 这无法在滚动线程上完成!
为兼顾锚定灵活性, 锚点定位采用了 记忆滚动偏移 和 滚动补偿 的结合方案。
-
定位元素首次显示或切换回退时, 会根据所有锚点引用的最新位置正确计算自身位置。
如果这些锚点引用位于不同滚动上下文, 则它们的总滚动偏移会被记忆, 后续布局会继续使用记忆的偏移, 即使这些元素后续被滚动。 (只记忆滚动偏移; 实际布局位置每次都会重新计算且保持准确。) 只有定位元素停止显示后重新显示或切换回退时才会重新计算。
-
唯一例外是默认锚点元素; 如果它相对于记忆滚动偏移发生滚动, 定位元素会随之移动。 因为这只是位置的纯移动, 定位元素不会改变尺寸或触发布局。
最终效果是锚点定位一般能“正常工作”, 不管锚定到什么元素, 但对于滚动的响应能力可能有限。
当为某元素确定回退样式时也会发生一次 锚点重算点; 如果因此更改了回退样式, 则与所选回退样式相关的 锚点重算点 结果会被采用。
当某元素 abspos 发生 锚点重算点时, 那么对于 abspos 的每个 anchor(即其锚点引用的元素), 会关联一个记忆滚动偏移, 等于该属性当前的所有滚动偏移 (即所有 滚动容器 祖先, 直到但不包括 abspos 的包含块)。 记忆滚动偏移还会考虑其它依赖滚动的位置变化, 如 position: sticky。 如果 abspos 有默认锚点元素, 即使 abspos 实际上没有对其进行 锚点引用, 也总会为其计算一次 记忆滚动偏移。
上述机制允许定位元素对其锚点引用的滚动位置响应一次, 但如有滚动发生, 定位元素不再表现为锚定于它们 (但仍会响应非滚动的移动)。 此问题无法普遍解决, 但可以对一个锚点引用的滚动做出响应; 具体来说,是默认锚点元素:
-
abspos 有一个默认锚点盒。
-
abspos 对其默认锚点盒或同一滚动上下文中的某元素有锚点引用,即下列之一:
-
abspos 在该轴上的自对齐属性值为anchor-center;
-
abspos的position-area 的值在该轴上非 none
-
至少有一个anchor()函数在 abspos 的已用 内边距属性上, 引用与 abspos 的 默认锚点盒 有相同最近滚动容器祖先的目标锚点元素。
-
注意: 如果 abspos 有 定位选项列表, 则其是否在某轴上进行滚动补偿也受应用的回退样式影响。
abspos 的 默认滚动偏移是水平和垂直轴的一对长度。 每个长度计算如下:
在对 abspos 完成布局后, 还会根据 默认滚动偏移进行额外移动, 效果类似于 transform(早于其它变换)。
注意: 记忆滚动偏移影响 anchor() 函数的值,而 默认滚动偏移直接在元素已确定其内边距属性、对齐等后额外移动。 通常效果等同, 但如 round(anchor(outside), 50px) 这样的非线性变换, 会暴露行为差异。
3.5. 条件隐藏:position-visibility 属性
名称: | position-visibility |
---|---|
值: | always | [ anchors-valid || anchors-visible || no-overflow ] |
初始值: | anchors-visible |
适用于: | 绝对定位盒 |
是否继承: | no |
百分比: | n/a |
计算值: | 按指定 |
规范顺序: | 按语法 |
动画类型: | 离散型 |
某些情况下,显示一个绝对定位盒可能没有意义。 本属性允许根据一些常见布局条件对这些盒子进行条件显示。
- always
-
该属性无效果。 (盒子无论锚点或溢出状态如何都显示。)
- anchors-valid
-
如果该盒子的任一必需锚点引用未能解析为目标锚点元素, 则盒子的visibility属性解析为force-hidden。
什么是必需锚点引用? anchor() 函数无回退值的情况;默认锚点有时也算? 这里需要更详细的说明。
- anchors-visible
-
如果盒子有默认锚点盒但该锚点盒是不可见或被中间盒裁剪, 则盒子的visibility属性解析为force-hidden。
- no-overflow
-
如果盒子在应用内边距修饰包含块和position-try后仍溢出, 则盒子的visibility属性解析为force-hidden。
注意: 这意味着如果 abspos 与其锚点在 DOM 相邻, 即使默认锚点被滚动出视口,也会保持可见,因为它们共同被同一个滚动容器裁剪。
需要确保裁剪定义与 View Transitions 一致, 后者也需要类似概念。
注意: 这样保证了在“链式锚点”场景下, 如果第一个 abspos 因本属性隐藏(锚点被滚动出视口), 则用它作锚点的另一个 abspos 也被隐藏, 而不是也漂浮在不合理的位置。
4. 基于锚点的尺寸
绝对定位盒可以在其尺寸属性中使用anchor-size()函数, 用以引用一个或多个锚点盒的尺寸。 anchor-size()函数会解析为<length>。 仅允许用于允许的 @position-try 属性(其他场景无效)。
4.1. anchor-size() 函数
名称: | width, height, min-width, min-height, max-width, max-height, top, left, right, bottom, margin-top, margin-left, margin-right, margin-bottom |
---|---|
新增值: | <anchor-size()> |
anchor-size() = anchor-size( [ <anchor-name> || <anchor-size> ]? , <length-percentage>? ) <anchor-size> = width | height | block | inline | self-block | self-inline
anchor-size()函数类似于anchor(), 参数一致, 只是 <anchor-side> 关键字被 <anchor-size> 取代, 表示两侧之间的距离。
物理 <anchor-size> 关键字 (width 和 height) 分别表示目标锚点元素的宽度和高度。 不同于anchor(),不限制轴向对应关系; 例如 width: anchor-size(--foo height); 是合法的。
逻辑 <anchor-size> 关键字 (block、inline、self-block、 self-inline) 会根据盒子的 书写模式 (对于 self-block 和 self-inline), 或盒子的包含块 书写模式 (对于 block 和 inline)来映射到物理关键字。
如果省略了 <anchor-size> 关键字, 则默认与 anchor-size() 所用的属性轴向匹配的关键字行为一致。 (如 width: anchor-size() 等价于 width: anchor-size(width)。)
anchor-size()函数表示可解析锚点尺寸函数时,会在计算值阶段 (通过样式与布局交错), 解析为 <length> 即目标锚点元素在指定轴上的相关边界之间的距离 (或左右,或上下,依据指定轴)。
4.1.1. anchor-size() 的解析
只有以下所有条件均成立时,anchor-size() 函数才是一个可解析锚点尺寸函数:
-
应用于绝对定位盒。
-
对于使用该函数的盒子,存在一个目标锚点元素,且函数中指定了 <anchor-name> 值。
如果以上任一条件不成立, anchor-size() 函数会取其回退值作为解析结果。 如果未指定回退值, 则引用它的声明在计算值阶段无效。
5. 溢出处理
锚点定位虽然强大,但也可能不可预测。 锚点盒可能出现在页面任意位置, 所以以任何特定方式定位盒子 (例如在锚点上方或右侧) 都可能导致定位盒溢出其包含块 或部分出现在屏幕外。
为缓解此问题,绝对定位盒 可以使用 position-try-fallbacks 属性, 引用多个定位/对齐属性的备选集合 (可来自盒子的现有样式, 也可在 @position-try 规则中指定), 用户代理可在盒子初始位置溢出时依次尝试这些备选方案。 每个方案依次应用, 第一个不会导致盒子溢出其包含块的方案即为最终选用方案。
position-try-order 允许根据定义的可用空间对这些选项进一步排序, 如果更重要的是让盒子拥有尽可能多的空间, 可优先考虑空间而非声明顺序。
5.1. 提供回退选项:position-try-fallbacks 属性
名称: | position-try-fallbacks |
---|---|
值: | none | [ [<dashed-ident> || <try-tactic>] | <'position-area'> ]# |
初始值: | none |
适用于: | 绝对定位盒 |
是否继承: | no |
百分比: | n/a |
计算值: | 按指定 |
规范顺序: | 按语法 |
动画类型: | 离散型 |
该属性提供一组备用定位样式, 当绝对定位盒溢出其内边距修饰包含块时尝试使用。 此定位选项列表初始为空。
列表里每个逗号分隔的项是一个独立选项: 可以是@position-try块的名称, 或一个<try-tactic>,代表对盒子现有计算样式的自动变换。
各值含义如下:
- none
-
该属性无效果; 盒子的定位选项列表为空。
- <dashed-ident>
-
如果存在同名的@position-try规则, 则将其关联的定位选项加入定位选项列表。
否则, 该值无效果。
- <try-tactic>
-
会根据指定关键字交换策略, 自动从盒子的计算样式创建一个定位选项, 并将构造出的定位选项加入盒子的定位选项列表。 并添加到定位选项列表。
<try-tactic> = flip-block || flip-inline || flip-start
- flip-block
-
交换块轴上的值(比如 margin-block-start 和 margin-block-end), 实质上是在内联轴线上镜像。
- flip-inline
- flip-start
-
交换start 属性的值, 以及end属性的值 (比如 margin-block-start 和 margin-inline-start), 实质上是沿对角线镜像 (从start-start角到end-end角)。
如给出多个关键字, 则依次组合变换, 生成一个 定位选项。
- <dashed-ident> || <try-tactic>
-
结合前两种选项的效果: 如果有同名的@position-try规则, 先将其定位选项应用到基础样式, 再按指定的<try-tactic>变换并加入盒子的定位选项列表。
否则不做任何处理。
- <'position-area'>
-
自动创建一个只包含指定position-area属性的定位选项。
-
如果directions在同一轴上为相反方向,则称为“对立”; 否则(指定不同轴时)为“垂直”。
-
确定 el 上允许的 @position-try 属性的指定值, 记为 styles。
-
对 styles 进行变量替换、env()函数, 以及类似的任意替换函数。
对于 env()函数, 若引用的环境变量与方向或轴相关 (如 safe-area-inset-top), 则切换引用的 环境变量对应directions。
例如,若写有 top: env(safe-area-inset-top);,且 directions 为上和左, 则 env() 会按 env(safe-area-inset-left) 解析。 (接下来,会交换到 left 属性。) -
交换 styles 中对应 directions 的相关属性值。
注意: 如果方向在同一轴上为对立, 某些属性(如 width 或 align-self) 不会交换, 因为它们在两个方向上自身关联, 但它们的值可能在下一步被修改。
-
交换后按如下方式调整属性值以匹配新方向:
-
对于内边距属性, 改变 anchor()函数指定的边, 保持与新方向的相对关系与原方向一致。
如使用<percentage>, 且 directions 为对立, 则改为 100% 减去原百分比。
例如,“top”和“left”交换时, margin-top: anchor(bottom) 会变成 margin-left: anchor(right)。若“top”和“bottom”交换, margin-top: anchor(20%) 会变成 margin-bottom: anchor(80%)。
-
对于尺寸属性, 改变 anchor-size() 函数指定的轴, 保持与新方向的相对关系与原方向一致。
-
对于自对齐属性, 若 directions 为对立, 则改变指定的 <self-position>(或 left/right 关键字), 保持与新方向的相对关系与原方向一致。
例如,“top”和“bottom”交换时, align-self: start 会变成 align-self: end。但 align-self: center 保持不变, 因为它在两个方向的关系一致。
类似地,align-self: first baseline 也保持不变, 因为它是<baseline-position>而非<self-position>。
-
对于position-area, 改变值以保证position-area 网格选中的行/列与新方向的关系一致。
-
-
返回 styles。
5.2. 确定回退顺序:position-try-order 属性
名称: | position-try-order |
---|---|
值: | normal | <try-size> |
初始值: | normal |
适用于: | 绝对定位盒 |
是否继承: | no |
百分比: | n/a |
计算值: | 按指定 |
规范顺序: | 按语法 |
动画类型: | 离散型 |
该属性指定定位选项列表将被尝试的顺序。
<try-size> = most-width | most-height | most-block-size | most-inline-size
- normal
-
按定位选项在position-try-fallbacks中指定的顺序依次尝试。
- most-width
- most-height
- most-block-size
- most-inline-size
- most-height
-
对定位选项列表中的每个条目,应用该定位选项到盒子, 并找出由这些样式产生的内边距修饰包含块的指定尺寸。 按此尺寸稳定排序定位选项列表, 最大的排在前面。
.anchor{ anchor-name : --foo; } .list{ position : fixed; position-anchor : --foo; position-area : block-end span-inline-end; align-self : start; position-try-fallbacks : --bottom-scrollable, flip-block, --top-scrollable; position-try-order : most-height; } @position-try --bottom-scrollable{ align-self : stretch; } @position-try --top-scrollable{ position-area : block-start span-inline-end; align-self : stretch; }
flip-block 自动生成的选项和 --top-scrollable选项总会获得相同的可用高度, 因为二者都在垂直方向上从包含块顶部拉伸到锚点顶部, 所以会保留它们的指定顺序。 这使盒子首先尝试按自然高度与锚点对齐 (使用align-self: end,自动翻转自基础样式), 若仍然溢出, 则会退到填满空间并可滚动的形式。
5.3. position-try 速记属性
名称: | position-try |
---|---|
值: | <'position-try-order'>? <'position-try-fallbacks'> |
初始值: | 见各属性 |
适用于: | 见各属性 |
是否继承: | 见各属性 |
百分比: | 见各属性 |
计算值: | 见各属性 |
动画类型: | 见各属性 |
规范顺序: | 按语法 |
该速记属性同时设置position-try-fallbacks和position-try-order。 如果省略<'position-try-order'>, 则取属性的初始值。
5.4. @position-try 规则
@position-try 规则 定义一个具有指定名称的定位选项, 可包含一组定位属性, 可通过position-try-fallbacks应用到盒子上,
@position-try规则的语法为:
@position-try <dashed-ident> { <declaration-list> }
前导中的<dashed-ident>为规则名称。 如声明多个同名@position-try规则, 以文档顺序最后一个为准。
@position-try规则仅接受以下属性:
在<declaration-list>中的属性使用!important是无效的。 这样做只会使该属性无效,不会使整个@property-try规则无效。
所有@position-try中的属性会作为定位回退来源应用到盒子上, 该来源是新级联来源, 介于作者来源和动画来源之间。
类似动画来源, 使用revert 值时, 效果如同该属性属于作者来源, 因此会回退到用户来源。 (和动画来源一样,revert-layer没有特殊行为,按指定处理。)
注意: 允许的 @position-try 属性是仅影响盒子自身尺寸和位置的最小属性集合, 不会改变内容或其它样式。 这样大大简化了定位回退的实现, 同时满足响应可用空间移动锚点定位盒的基本需求。 由于这些规则会覆盖作者来源的普通声明, 也限制了@position-try声明与其他属性级联和继承的负面交互。 预计未来扩展容器查询 后可根据所用回退定位查询元素, 实现目前受限属性列表下无法实现的条件样式。
注意: 若多个盒子使用不同锚点但希望使用相同回退定位, 只需在anchor()中省略<anchor-name>,分别在每个盒子的position-anchor中指定锚点即可。
注意: 最常见的回退定位场景(如定位盒默认在锚点一侧,必要时翻到另一侧) 可以直接在position-try-fallbacks属性中用关键字自动实现, 完全无需@position-try规则。
5.5. 应用定位回退
当一个定位盒 (应用了其默认滚动偏移后) 溢出了其内边距修饰包含块, 且具有非空定位选项列表时, 会确定定位回退样式,以寻找能避免溢出的选项。
这些修改后的样式通过交错应用到元素, 因此会影响计算值(并可触发过渡等), 即使它们依赖布局和已用值。
-
令current styles为abspos当前的已用样式(可能是之前回退的结果)。
-
断言:前一步未找到能避免溢出的定位选项。
-
返回current styles。
注意: 后代溢出el不会影响本计算, 只看el自身边距盒。
注意: 因为我们故意跳过当前有效的定位选项, 它不会更新其记忆滚动偏移; 如果没有其他回退可用,只保留当前样式, 所有记忆滚动偏移保持不变。
在一次完整布局过程中, 一旦盒子确定了其回退样式(或确定未使用), 后续盒子的布局不会改变该决定。
换句话说,布局不会“回溯”。
ResizeObserver
事件被确定和分发时:
-
如果盒子el是绝对定位, 则将其最后成功定位选项设置为其当前使用的允许的 @position-try 属性及其值。
-
否则,如果el有最后成功定位选项,且满足下列任一条件, 则移除其最后成功定位选项:
-
el不是绝对定位
-
el的position-try-fallbacks计算值发生变化
-
任何被el的position-try-fallbacks引用的@position-try规则被添加、移除或修改。
然后,确定定位回退样式为el, 并将其最后成功定位选项设置为当前使用的允许的 @position-try 属性及其值。
-
注意: 该记录/移除时机与最后记忆尺寸的处理方式完全一致。
实现可以选择对定位选项列表长度施加实现定义限制, 以限制可能产生的多余布局工作量。 该限制必须至少为五个。
#myPopover{ position : fixed; top : anchor ( --button bottom); left : anchor ( --button left); position-try-fallbacks : flip-inline, flip-block, flip-block flip-inline; /* 弹窗宽度至少与按钮一致 */ min-width:anchor-size ( --button width); /* 弹窗高度至少为2个菜单项 */ min-height:6 em ; }
6. 无障碍影响
需要注意的是,锚点定位并不会自动建立定位盒与其锚点之间的语义关系, 因为这种定位方式用途非常广泛。 作者不能仅依靠定位方式带来的视觉连接来实现元素之间的语义关联; 如果没有额外处理,这些元素在DOM中通常没有有意义的关系, 这会让诸如屏幕阅读器等非视觉用户代理难以甚至无法使用。
Web平台上已有及将来的许多特性, 都可以显式建立这种关系, 使非视觉用户代理也能受益。
例如,HTML中的Popover API 会自动将触发按钮与弹出元素关联起来, 包括自动调整Tab顺序; 它还会将触发按钮作为弹出层的隐式锚点元素, 这也便于使用锚点定位。
在更一般的场景下,
ARIA 特性如
aria-details
或 aria-describedby
属性
可在锚点元素上手动建立这种信息;
配合定位元素上的
role
属性,
非视觉用户代理就可以告知用户元素之间的关系,
并让用户自动在它们之间导航。
7. DOM 接口
7.1. CSSPositionTryRule 接口
CSSPositionTryRule
接口表示
@position-try 规则:
[Exposed =Window ]interface :
CSSPositionTryRule CSSRule {readonly attribute CSSOMString name ; [SameObject ,PutForwards =cssText ]readonly attribute CSSPositionTryDescriptors style ; }; [Exposed =Window ]interface :
CSSPositionTryDescriptors CSSStyleDeclaration {attribute CSSOMString ;
margin attribute CSSOMString ;
marginTop attribute CSSOMString ;
marginRight attribute CSSOMString ;
marginBottom attribute CSSOMString ;
marginLeft attribute CSSOMString ;
marginBlock attribute CSSOMString ;
marginBlockStart attribute CSSOMString ;
marginBlockEnd attribute CSSOMString ;
marginInline attribute CSSOMString ;
marginInlineStart attribute CSSOMString ;
marginInlineEnd attribute CSSOMString ;
margin-top attribute CSSOMString ;
margin-right attribute CSSOMString ;
margin-bottom attribute CSSOMString ;
margin-left attribute CSSOMString ;
margin-block attribute CSSOMString ;
margin-block-start attribute CSSOMString ;
margin-block-end attribute CSSOMString ;
margin-inline attribute CSSOMString ;
margin-inline-start attribute CSSOMString ;
margin-inline-end attribute CSSOMString ;
inset attribute CSSOMString ;
insetBlock attribute CSSOMString ;
insetBlockStart attribute CSSOMString ;
insetBlockEnd attribute CSSOMString ;
insetInline attribute CSSOMString ;
insetInlineStart attribute CSSOMString ;
insetInlineEnd attribute CSSOMString ;
top attribute CSSOMString ;
left attribute CSSOMString ;
right attribute CSSOMString ;
bottom attribute CSSOMString ;
inset-block attribute CSSOMString ;
inset-block-start attribute CSSOMString ;
inset-block-end attribute CSSOMString ;
inset-inline attribute CSSOMString ;
inset-inline-start attribute CSSOMString ;
inset-inline-end attribute CSSOMString ;
width attribute CSSOMString ;
minWidth attribute CSSOMString ;
maxWidth attribute CSSOMString ;
height attribute CSSOMString ;
minHeight attribute CSSOMString ;
maxHeight attribute CSSOMString ;
blockSize attribute CSSOMString ;
minBlockSize attribute CSSOMString ;
maxBlockSize attribute CSSOMString ;
inlineSize attribute CSSOMString ;
minInlineSize attribute CSSOMString ;
maxInlineSize attribute CSSOMString ;
min-width attribute CSSOMString ;
max-width attribute CSSOMString ;
min-height attribute CSSOMString ;
max-height attribute CSSOMString ;
block-size attribute CSSOMString ;
min-block-size attribute CSSOMString ;
max-block-size attribute CSSOMString ;
inline-size attribute CSSOMString ;
min-inline-size attribute CSSOMString ;
max-inline-size attribute CSSOMString ;
placeSelf attribute CSSOMString ;
alignSelf attribute CSSOMString ;
justifySelf attribute CSSOMString ;
place-self attribute CSSOMString ;
align-self attribute CSSOMString ;
justify-self attribute CSSOMString ;
positionAnchor attribute CSSOMString ;
position-anchor attribute CSSOMString ;
positionArea attribute CSSOMString ; };
position-area
它的 name
属性代表规则前导中声明的名称。
它的 style
属性代表规则主体中声明的属性,
按指定顺序排列。
读取时,必须返回 CSSPositionTryDescriptors
对象,
代表 @position-try at-rule,
具有以下属性:
- computed flag
-
未设置
- readonly flag
-
未设置
- declarations
-
规则中声明的描述符,按指定顺序排列。
- parent CSS rule
-
上下文对象
- owner node
-
Null
8. 附录:样式与布局交错
样式与布局交错是一种技术, 允许在布局过程中对子树进行样式更新, 从而可对元素的计算样式进行追溯更新。
这个概念不应出现在本规范, 可能应放到 Cascade, 但我需要一个草稿来引用。
注意: 样式与布局交错已用于容器查询和容器查询长度。 如 10cqw 这样的长度会根据查询容器的大小布局信息解析为计算长度, 当容器在布局间变化尺寸时也能触发 过渡。
允许的 @position-try 属性在解析回退时也会交错 (见 position-try)。
显然这里还需要补充很多细节, 但目前“按容器查询的做法处理”即可。 虽然那部分行为也没明确定义, 但至少在一定程度上是可互操作的。
9. 安全性考量
本文件未发现安全性问题。
10. 隐私考量
本文件未发现隐私问题。
11. 变更记录
自 2024年10月4日工作草案 以来的重要变更:
-
将 position-area 的中心轨默认对齐方式改为 center 对齐。 (Issue 11803)
-
定义了 伪元素的隐式锚点元素为其来源元素。 (Issue 11792)
-
重写了滚动的处理与响应方式(§ 3.4 考虑滚动), 使定位元素能够在锚点滚动时可能响应 (如首次渲染或更换回退样式时)。 (Issue 10999)
-
将 position-visibility 改为使用新定义的 visibility: force-hidden 值 而不是自定义概念,以更好地支持过渡。 (Issue 10182)
-
修正了锚点解析算法中的一些错误。 (Issue 11030,Issue 11170)
-
修正了<position-area>关键字列表中的一些错误。 (Issue 11372,Issue 11371)
-
定义了 anchor-scope 标识符为树作用域名称(因此与anchor name比较时有特殊规则)。 (Issue 10525,Issue 10526)
-
澄清了 position-area 的计算值不区分逻辑关键字的长短形式。 (Issue 11828)
-
澄清了某些 anchor() 的可解析性检查是在计算值阶段,而非解析阶段。 (Issue 10955)
-
对部分章节,特别是§ 3.1 position-area 属性,进行了编辑性重组。
另见更早的变更记录。