CSS `anchor-position` `anchor()` 函数与 `top`, `left` 坐标系

诶嘿!各位观众老爷们,大家好!我是你们的老朋友,bug终结者,今天咱们不聊风花雪月,来点硬核的——CSS anchor-positionanchor() 函数,以及它们跟 topleft 坐标系的那些不得不说的故事。准备好了吗?系好安全带,这趟旅程可能有点颠簸,但保证精彩!

第一幕:锚定,不只是船的专利

话说咱们前端开发,最头疼的事情之一就是元素的定位。绝对定位、相对定位、固定定位,各种定位方式让人眼花缭乱。但是!有没有想过,让一个元素像船抛锚一样,牢牢地锚定在另一个元素身上呢?这就是 anchor-positionanchor() 函数的用武之地。

anchor-position 属性定义了锚定框(anchor box)的默认位置,而 anchor() 函数则允许我们动态地引用锚定元素(anchor element)的属性,比如宽度、高度、甚至相对于视口的偏移量。

简单来说,anchor-position 决定了锚定元素“抛锚”的大致位置,而 anchor() 函数则提供了更精细的调整。

第二幕:anchor-position:你是我的东南西北

anchor-position 属性接受一个或两个值,用于指定锚定框相对于锚定元素的水平和垂直位置。这些值可以是预定义的关键字(top, bottom, left, right, center),也可以是百分比值。

  • 一个值: 如果只指定一个值,则水平和垂直位置都使用相同的值。例如,anchor-position: top; 等价于 anchor-position: top top;

  • 两个值: 第一个值指定垂直位置,第二个值指定水平位置。例如,anchor-position: top left; 表示锚定框位于锚定元素的顶部和左侧。

咱们先来几个小例子热热身:

/* 将锚定框定位到锚定元素的顶部中心 */
.anchored-element {
  position: absolute; /* 必须是绝对定位或固定定位 */
  anchor-position: top center;
}

/* 将锚定框定位到锚定元素的底部右侧 */
.anchored-element {
  position: absolute;
  anchor-position: bottom right;
}

/* 将锚定框定位到锚定元素的中心 */
.anchored-element {
  position: absolute;
  anchor-position: center; /* 等价于 center center */
}

第三幕:anchor() 函数:精确制导,指哪打哪

anchor() 函数才是真正的大杀器!它允许我们读取锚定元素的各种属性,并将其用于定位锚定框。它的语法是:

anchor(<anchor-element>, <property> <fallback-value>?)
  • <anchor-element>:锚定元素的选择器。可以是 ID 选择器 (#anchor),也可以是其他选择器。

  • <property>:要读取的锚定元素的属性。可以是 top, left, width, height, 等等。

  • <fallback-value> (可选):如果锚定元素不存在或属性无法读取,则使用的默认值。

让我们用几个例子来感受一下 anchor() 函数的强大:

<div id="anchor-element">我是锚定元素</div>
<div id="anchored-element">我是锚定框</div>
#anchor-element {
  width: 200px;
  height: 100px;
  background-color: lightblue;
  position: relative; /* 重要的,作为定位上下文 */
}

#anchored-element {
  position: absolute;
  background-color: lightcoral;
  /* 将锚定框定位到锚定元素的右侧,距离顶部 20px */
  top: calc(anchor(#anchor-element, top) + 20px);
  left: anchor(#anchor-element, right);
  width: 100px;
  height: 50px;
}

在这个例子中,#anchored-elementtop 属性使用了 anchor(#anchor-element, top),这意味着它的顶部位置将会是 #anchor-element 的顶部位置加上 20px。left 属性使用了 anchor(#anchor-element, right),这意味着它的左侧位置将会是 #anchor-element 的右侧位置。

第四幕:topleft:坐标系的秘密

现在,咱们来聊聊 topleft 坐标系。这俩哥们儿是定位的基础,理解它们至关重要。

  • top 指定元素上边缘与其包含块上边缘之间的距离。
  • left 指定元素左边缘与其包含块左边缘之间的距离。

但是!要注意的是,这个“包含块”可不是随便指定的。它取决于元素的 position 属性:

position 属性 包含块
static 无效。topleftrightbottom 属性对静态定位的元素没有影响。
relative 元素正常流中的位置。topleft 属性会相对于元素自身在正常流中的位置进行偏移。
absolute 最近的已定位祖先元素(positionabsoluterelativefixedsticky 的元素)。如果没有已定位的祖先元素,则包含块是初始包含块(通常是 <html> 元素)。
fixed 视口(浏览器窗口)。topleftrightbottom 属性相对于视口进行定位。
sticky 在滚动容器中,元素会表现得像 relative,直到它滚动到特定的阈值,然后会表现得像 fixedtopleftrightbottom 属性指定了元素何时应该被视为 fixed

理解了包含块的概念,才能正确地使用 topleft 属性。

第五幕:anchor() 函数与 topleft 的激情碰撞

现在,让我们把 anchor() 函数和 topleft 属性结合起来,看看能擦出什么样的火花。

<div id="container">
  <div id="anchor-element">我是锚定元素</div>
  <div id="anchored-element">我是锚定框</div>
</div>
#container {
  width: 500px;
  height: 300px;
  background-color: #f0f0f0;
  position: relative; /* 作为定位上下文 */
}

#anchor-element {
  width: 200px;
  height: 100px;
  background-color: lightblue;
  position: absolute;
  top: 50px;
  left: 50px;
}

#anchored-element {
  position: absolute;
  background-color: lightcoral;
  width: 100px;
  height: 50px;
  /* 将锚定框定位到锚定元素的底部,水平居中 */
  top: anchor(#anchor-element, bottom);
  left: calc(anchor(#anchor-element, left) + anchor(#anchor-element, width) / 2 - width / 2);
}

在这个例子中,#anchored-elementtop 属性使用了 anchor(#anchor-element, bottom),这意味着它的顶部位置将会是 #anchor-element 的底部位置。而 left 属性则更加复杂,它使用了 anchor(#anchor-element, left)anchor(#anchor-element, width) 来计算 #anchored-element 的水平居中位置。

第六幕:高级技巧:fallback-value 和单位

anchor() 函数还有一个可选的 fallback-value 参数,用于指定当锚定元素不存在或属性无法读取时使用的默认值。这可以避免出现错误或意外的布局。

#anchored-element {
  position: absolute;
  top: anchor(#non-existent-element, top, 0px); /* 如果 #non-existent-element 不存在,则使用 0px */
  left: anchor(#non-existent-element, left, 50%); /* 如果 #non-existent-element 不存在,则使用 50% */
}

另外,需要注意的是,anchor() 函数返回的值是带有单位的,例如 px%。因此,在进行计算时,需要确保单位一致。可以使用 calc() 函数来进行单位转换。

#anchored-element {
  position: absolute;
  width: calc(anchor(#anchor-element, width) / 2); /* 将锚定框的宽度设置为锚定元素宽度的一半 */
}

第七幕:实际应用场景

anchor-positionanchor() 函数在实际开发中有很多应用场景,例如:

  • 工具提示(Tooltips): 将工具提示框锚定到目标元素,并根据目标元素的位置动态调整工具提示框的位置。

  • 下拉菜单(Dropdown Menus): 将下拉菜单锚定到触发按钮,并根据触发按钮的位置动态调整下拉菜单的位置。

  • 模态框(Modal Boxes): 将模态框锚定到触发按钮,并根据触发按钮的位置动态调整模态框的位置。

  • 自定义组件: 构建需要根据其他元素位置进行动态调整的自定义组件。

第八幕:兼容性注意事项

虽然 anchor-positionanchor() 函数非常强大,但需要注意的是,它们的兼容性还不是很好。截止到我写这篇文章的时候 (2024-10-27),只有 Chrome 和 Edge 的最新版本支持它们。因此,在使用它们时,需要进行兼容性测试,并提供适当的降级方案。

第九幕:一个更复杂的例子:自定义 Tooltip

咱们来个更复杂点的例子,用 anchor-positionanchor() 函数实现一个自定义的 Tooltip。

<div id="container">
  <button id="target-button">Hover Me</button>
  <div id="tooltip">
    This is a tooltip!
  </div>
</div>
#container {
  width: 300px;
  height: 200px;
  position: relative;
  background-color: #eee;
}

#target-button {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  padding: 10px 20px;
  background-color: #007bff;
  color: white;
  border: none;
  cursor: pointer;
}

#tooltip {
  position: absolute;
  background-color: rgba(0, 0, 0, 0.8);
  color: white;
  padding: 5px 10px;
  border-radius: 5px;
  font-size: 12px;
  visibility: hidden; /* 默认隐藏 */
  opacity: 0;
  transition: visibility 0s, opacity 0.2s linear;
  /* 初始位置:放在按钮上方,水平居中 */
  anchor-position: top center;
  top: calc(anchor(#target-button, top) - 10px); /* 向上偏移一点 */
  left: calc(anchor(#target-button, left) + anchor(#target-button, width) / 2 - width / 2);
}

#target-button:hover + #tooltip {
  visibility: visible; /* hover 时显示 */
  opacity: 1;
}

这个例子中,我们将 Tooltip 默认隐藏,当鼠标悬停在按钮上时,Tooltip 才会显示。我们使用 anchor-position: top center; 将 Tooltip 默认放在按钮上方居中的位置,并通过 topleft 属性使用 anchor() 函数进行微调。

第十幕:总结与展望

好了,各位观众老爷们,今天的讲座就到这里了。我们一起学习了 CSS anchor-positionanchor() 函数,以及它们与 topleft 坐标系的关系。希望通过今天的学习,大家能够更加灵活地控制元素的定位,打造出更加精美的用户界面。

虽然 anchor-positionanchor() 函数的兼容性还不是很好,但我相信,随着浏览器的不断发展,它们一定会得到更广泛的支持。未来,我们可以期待更多的 CSS 新特性,让我们的开发工作更加高效、便捷。

记住,前端开发的道路是漫长而充满挑战的,但只要我们不断学习、不断探索,就一定能够成为一名优秀的前端工程师!

感谢大家的观看!我们下期再见! 别忘了点赞投币加关注哦! 溜了溜了~

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注