position-try-fallbacks

Avatar of Juan Diego Rodríguez
Juan Diego Rodríguez

DigitalOcean 提供适合您旅程各个阶段的云产品。立即开始使用 价值 200 美元的免费积分!

CSS position-try-fallbacks 属性接受一个包含不同选项的列表,这些选项用于“目标”元素相对于“锚点”元素进行position 定位,通过尝试声明的逗号分隔的选项列表来实现。如果第一个选项没有足够的可用空间来显示目标元素,则会尝试下一个选项,依此类推,这与在font-family设置备用字体非常类似。

.target {
  position: absolute;
  position-anchor: --my-anchor;
  inset-area: top left;
  position-try-fallbacks: flip-inline, inset-area(bottom left), --my-custom-position;
}

作为背景信息,这都是CSS 锚点定位规范的一部分,它是一套许多功能的集合,这些功能协同工作以定位一个元素(我们称之为“目标”)到另一个元素(我们称之为“锚点”)。

注意:CSS 规范将该属性称为position-try-fallbacks,但截至本文撰写之时,Chromium 浏览器的实现称为position-try-options,具有相同的取值集。未来,规范可能会更改,或者浏览器可能会更新其实现以保持一致。在此之前,建议使用position-try 简写属性。因此,本文中的所有演示都使用position-try-options

语法

position-try-fallbacks: none | [ [<dashed-ident> || <try-tactic>] | inset-area( <'inset-area'> ) ]#
  • 初始值:none
  • 应用于:绝对定位元素
  • 继承:
  • 百分比:n/a
  • 计算值:如指定
  • 规范顺序:按语法
  • 动画类型:离散

/* Custom @try-position */
position-try-fallbacks: --my-custom-position;
position-try-fallbacks: --myCustomPosition;

/* <try-tactic> */
position-try-fallbacks: flip-block;
position-try-fallbacks: flip-inline;
position-try-fallbacks: flip-start;
position-try-fallbacks: flip-block flip-inline;

/* `<dashed-ident>` || `<try-tactic>` */
position-try-fallbacks: --my-custom-position flip-block;
position-try-fallbacks: --myCustomPosition flip-block flip-inline;

/* inset-area( <'inset-area'> ) */
position-try-fallbacks: inset-area(bottom center);
position-try-fallbacks: inset-area(top left);

/* All can be together! */
position-try-fallbacks: --my-custom-position, flip-block flip-inline, --my-custom-position flip-block, inset-area(top left);

position-try-fallbacks 属性接受一个逗号分隔的选项列表,用于在目标元素超出其包含块时定位该元素。顺序按照书写顺序,但可以使用position-try-order 属性进行排序。

  • none: 将目标的定位选项列表清空。
  • <dashed-ident>: 将一个自定义的@position-try 选项(具有给定名称)添加到选项列表中。如果不存在匹配的@position-try,则该属性不会有任何效果。该值称为“虚线”标识符,因为它必须以两个连字符 (–) 为前缀。
  • <try-tactic>: 通过沿三个轴之一翻转目标的当前位置来创建选项列表,每个轴都由一个不同的关键字定义。它们也可以组合起来,以累加其效果。

  • <dashed-ident> || <try-tactic>: 将一个自定义的@try-option 和一个<try-tactic> 组合在一起,通过按照指定的方式翻转自定义的@position-try 来创建一个单个选项列表。<try-tactic> 关键字也可以组合起来,以累加其效果。

  • inset-area( <'inset-area'> ): 使用围绕包装函数的inset-area 语法将目标移动到新的inset-area

注意:根据规范,inset-area( <'inset-area'> ) 函数不存在,inset-area 值不需要包装器,但已经实现了position-anchor 属性的浏览器仍然使用它。

为什么我们需要position-try-options

将元素相对于锚点进行定位似乎是一个两步操作: (1) 将目标链接到锚点元素,以及 (2) 将目标定位到锚点周围。但是,锚点元素可以位于页面上的任何位置,甚至由于滚动、缩放、动画等而改变位置。因此,目标元素很容易没有足够的空间相对于锚点进行定位,并超出其包含块(默认情况下为视窗)。

这是很正常的现象;我们无法阻止元素在滚动时超出屏幕,但我们可以通过最大化其屏幕显示时间来改善体验。

锚点定位的常见用例是工具提示,它们有一个反复出现的问题,即过多的超出屏幕显示。例如,位于元素顶部的工具提示在向下滚动时会超出屏幕。

Skeleton text with an overflowing tooltip at the top of an element

传统上,避免这种情况的唯一方法是使用 JavaScript 动态更改工具提示的位置,但使用position-try-fallbacks,我们只需要 CSS 就能实现相同的效果。

Skeleton text with a smart tooltip that doesn't overflow at the bottom of the element

使用position-try-options

要在 CSS 中开始使用position-try-fallbacks 属性,我们需要我们的主要角色:锚点元素和目标元素。

<div class="anchor">My Anchor</div>
<div class="target">My Target</div>

以及一些 CSS 代码将它们链接在一起

.anchor {
  anchor-name: --my-anchor;
}

.target {
  position: absolute;
  position-anchor: --my-anchor;
}

如果我们没有以任何特殊方式定位目标,它将停留在其默认锚点下方。我们可以使用anchor() 函数将目标沿着目标的内边距属性移动,或者使用inset-area 属性。无论您选择哪种选项,请记住它,以便稍后使用。

.target {
  position: absolute;
  position-anchor: --my-anchor;

  inset-area: top;
  /* or */
  bottom: anchor(top);
}

我们的目标位于其锚点上方,但问题在于当我们向下滚动时,目标会向我们挥手告别,因为它消失在视窗之外。这个目标可能是一个工具提示或其他弹出窗口,用于显示有关其锚点元素的相关信息,但现在锚点可见,而其相关目标不可见。

这是一个由来已久的问题,最佳解决方案总是包括使用 JavaScript 来实现一个不会超出屏幕的工具提示,甚至使用像Popper.js 这样的库。

使用position-try-fallbacks,我们可以编写一个包含可能位置的列表,以便在我们的目标超出视窗时使用。您的浏览器将按照书写顺序尝试这些选项,直到找到一个不会超出屏幕的选项,或者用完所有选项。

inset-area( <'inset-area'> )

为了简单起见,我们有inset-area() 包装函数,它接受您的常规inset-area 属性可以接受的所有值。我们可以给出一个包含可能inset-area 选项的列表,当目标超出屏幕时,它将尝试这些选项。例如,将目标从顶部移动到底部。

.target {
  position: absolute;
  position-anchor: --my-anchor;

  inset-area: top;
  position-try-fallbacks: inset-area(bottom);
}

我们还可以给出一个包含多个inset-area() 函数的列表,以便在需要时将目标在锚点周围移动

.target {
  position: absolute;
  position-anchor: --my-anchor;

  inset-area: top left;
  position-try-fallbacks:
    inset-area(top), inset-area(top right), 
    inset-area(right), inset-area(bottom), 
    inset-area(bottom right);
}

<dashed-ident>

我们可以使用@position-try at 规则来创建自定义的定位选项,以修改目标的位置。它接受几乎所有可以修改元素位置的属性

  • 内边距属性 (top, left, bottom, right, inset-block, inset-inline, 等)

  • 外边距属性 (margin, margin-block, margin-inline, 等)

  • 尺寸属性 (width, min-width, height, max-height, inline-size, block-size, 等,)

  • 自身对齐属性 (align-self, justify-self, place-self)

  • 位置锚点属性 (position-anchor, inset-area)

因此,例如,我们可以在目标超出屏幕时使其变小

@position-try --smaller-target {
  width: 50px;
}

.target {
  position: absolute;
  position-anchor: --my-anchor;
  inset-area: top;
  position-try-fallbacks: --smaller-target;

  width: 120px;
  aspect-ratio: 1;
}

我告诉过您,如果使用内边距属性的anchor() 函数inset-area 属性来定位锚点,请记住这一点。为什么?因为如果我们在原始声明中不一致,则使用@try-position at 规则来更改它们将不起作用。例如,以下--custom-bottom 将不起作用,因为我们没有使用相同的方法来定位目标。

@position-try --custom-bottom {
  width: 50px;
  top: anchor(bottom);
}

.target {
  /* ... */
  inset-area: top;
  position-try-fallbacks: --custom-bottom;
}

我们需要使定位方法匹配。

@position-try --custom-bottom {
  width: 50px;
  inset-area: bottom;
}

<try-tactic>

<try-tactic> 值根据指定的尝试策略交换其位置,从而创建一个新的位置选项。它有三个可能的关键词,每个关键词指定了哪些值将被交换,本质上是将目标从一侧更改到另一侧。

flip-block 关键词交换块轴中的值。

flip-block example. The anchor changes from the top to the bottom

flip-inline 关键词交换内联轴中的值。

flip-inline example. The anchor changes from the left to the right

flip-start 关键词对角线交换值。我不得不承认,flip-start 是一个奇怪的 <try-tactic>,对我来说仍然有点令人困惑。在单个值的情况下,它会将它们定位在相邻的一侧。

flip-start with a single value example. The target changes from the left to the top

但如果目标有两个值,它会将它们定位在对角的角落。至少在理论上,在实践中,它只能将目标从右上角翻转到左下角,反之亦然,在 LTR 上。

flip-start with two values example (LTR). The target changes from the right top side to the left bottom side

以及从左上角翻转到右下角,反之亦然,在 RTL 上。

flip-start with two values example (RTL). The target changes from the left top side to the right bottom side

如果我们想要一个无论文本方向如何都能翻转到对角角落的目标,我们可以组合 flip-blockflip-inline 关键词。它将首先在块轴上翻转锚点,然后在内联轴上翻转。

flip-block and flip-inline example. The target goes from the left top to the left bottom, and ends up on the right bottom

最后,我们可以将 flip-start 值与 flip-blockflip-inline 组合,将目标翻转到另一个相邻的一侧。

flip-start and flip-block example. The target goes from the left side to the top, and ends up on the bottom

顺序很重要,所以编写 flip-start flip-block 将导致与 flip-block flip-start 不同的位置。在后者中,flip-block 关键词首先执行,由于目标不在块轴上,因此它没有任何效果,并且被忽略。

flip-block and flip-start example. The target ignores the flip-block keyword and goes straight to the bottom

<dashed-ident> || <try-tactic>

最后,我们可以将一个自定义 @try-position 选项与一个或多个 <try-tactic> 关键词组合起来,创建一个新的位置选项,本质上是翻转 @try-position 属性。例如,自定义位置选项……

@try-position --custom-right {
  inset-area: top;
  align-self: start;
}

……如果使用 flip-block 关键词翻转,将计算为以下结果

@try-position --custom-right {
  inset-area: bottom;
  align-self: end;
}

演示

规范

position-try-options 属性在 CSS 锚点定位模块 1 级规范 中定义,该规范目前处于工作草案状态。这意味着在该功能成为正式候选推荐以供实施之前,可能会有很多变化。

浏览器支持

Data on support for the css-anchor-positioning feature across the major browsers from caniuse.com

更多信息和教程