CSS anchor锚点定位:让你的网页精准导航

AI 概述
一、快速了解 CSS 锚点定位二、CSS 锚点定位语法详解1. 锚点的设置与引用 anchor-name、position-anchor2.锚点的位置表示 anchor()3. 锚定居中 anchor-center4. 更人性化的定位方式 inset-area5. 锚点尺寸 anchor-size6. 动态调整位置 position-try-options三、和 popover 配合使用四、总结 Chrome 125...
目录
文章目录隐藏
  1. 一、快速了解 CSS 锚点定位
  2. 二、CSS 锚点定位语法详解
  3. 三、和 popover 配合使用
  4. 四、总结

Chrome 125 近期正式支持 CSS 锚点定位,此特性一出有望像 CSS 滚动驱动动画一样,在 Web 前端开发领域掀起一场变动。利用这一特性,以前很多必须依赖 JavaScript 的解决方案,现在都可以通过纯 CSS 来实现,而且更加简单、灵活。让我们一同来看一看。

一、快速了解 CSS 锚点定位

在过去,要实现一个元素定位,通常需要一个相对定位。比如这样一个 tooltip:

CSS 锚点定位

如果不借助 JS,让这个气泡位于按钮的正上方,就只能约束HTML结构,让这个气泡位于按钮内部。

<button>
  BUTTON
  <tooltip>我是 tooltip</tooltip>
</button>

并且设置按钮为相对定位,才能通过绝对定位实现气泡位于按钮的正上方。

button{
  position: relative;
}
tooltip{
  position: absolute;
  bottom: 100%;
  left: 50%;
  transform: translateX(-50%)
}

虽然可以实现,但是局限性很多。比如HTML要求严格,只能是嵌套结构,换种结构就不行了,还有,如果父级有超出隐藏的样式,这个气泡也会被裁剪掉。因此,一般框架里不会采用这种 CSS 实现,都是通过JS动态去获取位置来实现的。

现在有了CSS锚点定位特性,一切都好办了。

首先是对结构无任何要求,可以是页面上的任意地方的元素:

<button>BUTTON</button>
<tooltip>我是 tooltip</tooltip>

由于没有嵌套关系,所以我们要手动的指定一下(不然谁知道该怎么定位呢?),这里是通过anchor-nameposition-anchor将两个元素关联(锚定)起来,如下:

button{
  anchor-name: --anchor-el;
}
tooltip{
  position: absolute;
  position-anchor: --anchor-el;
}

最后,再设置定位就行了,关键实现如下:

tooltip{
  bottom: anchor(top);
  left: anchor(center);
  transform: translateX(-50%)
}

这样就能实现任意两个元素的锚定了。

CSS 锚点定位

完整代码:

button{
  border: 0;
  font-size: 24px;
  border-radius: 8px;
  padding: 10px 24px;
  color: royalblue;
  background: none;
  overflow: hidden;
  text-transform: uppercase;
  background-color: rgba(from royalblue r g b/.2);
  cursor: pointer;
  transition: .2s;
  anchor-name: --anchor-el;
}
button:hover{
  background-color: rgba(from royalblue r g b/.4);
}
tooltip{
  position: fixed;
  position-anchor: --anchor-el;
  bottom: anchor(top);
  left: anchor(center);
  transform: translateX(-50%);
  padding: 10px;
  background-color: #333;
  color: #f0f0f0;
  text-align: center;
  border-radius: 4px;
  margin: 0 0 5px;
  box-shadow: 0 2px 6px rgba(0, 0, 0, 0.25);
  font-size: 14px;
  filter: drop-shadow(4px 4px 4px rgba(50, 50, 50, 0.3));
  transition: .2s;
  border: 0;
  overflow: visible;
  width: max-content;
}
tooltip::after{
  content: "";
  position: absolute;
  top: 100%;
  left: 50%;
  margin-left: -5px;
  border-width: 5px;
  border-style: solid;
  border-color: black transparent transparent transparent;
}

是不是非常灵活呢?不过这里出现了一些从未见过的属性和方法,下面再来具体介绍

二、CSS 锚点定位语法详解

为了实现这样一个功能,CSS新推出了很多属性和方法,如下。

1. 锚点的设置与引用 anchor-name、position-anchor

这个前面已经用到了,主要是anchor-nameposition-anchor两个属性,他们俩用一个唯一的标识符链接起来。需要注意的是,这个标识符必须要以双短横线开头,和 CSS 变量名是一样的,其他的则无效。

button{
  anchor-name: anchor-el; /*属性值无效*/
}
button{
  anchor-name: --anchor-el;
}
tooltip{
  position: absolute;
  position-anchor: --anchor-el;
}

你可以理解为把设置anchor-name的元素当做是以前的相对定位元素(锚点元素),而设置position-anchor的元素就当成普通绝对定位元素就行了。

CSS 锚点定位语法详解

另外,如果标识符有重复,比如有多个button,都是相同的anchor-name,那么会以最后一个为准。

CSS 锚点定位

2.锚点的位置表示 anchor()

前面说了,设置position-anchor的元素可以当做是普通的绝对定位。既然是定位,那就需要设置坐标,比如lefttop值。由于不是固定的值,为了,这里又推出了一系列定位函数,如下

anchor(left)
anchor(center)
anchor(right)
anchor(top)
anchor(bottom)

比如anchor(left)表示锚定元素的最左侧,anchor(top)表示锚定元素的最上侧,依次类推,下面是一张示意图:

锚点的位置表示 anchor()

值得注意的是,anchor(center)表示既可以表示水平居中,也可以表示垂直居中,这是由使用方式决定的。

top: anchor(center); /*垂直居中*/
left: anchor(center); /*水平居中*/

回到上一章的例子,我们要实现一个朝上居中的气泡,所以定位元素的bottom要刚好处于锚定元素的上方,然后水平方向上是常用的居中方式,先定位到中间,然后反向位移自身的一半,具体实现如下:

tooltip{
  bottom: anchor(top);
  left: anchor(center);
  transform: translateX(-50%)
}

水平方向的居中看着不是特别优雅,而且还占用了transform,可能不是特别灵活,下面来看另一个实现

3. 锚定居中 anchor-center

上面水平居中用到了lefttransform来实现,其实还有新的实现方式,那就是anchor-center,不过这需要配合justify-selfalign-self使用。

比如要水平居中,可以直接使用:

tooltip{
  bottom: anchor(top);
  justify-self: anchor-center;
}

如果要垂直居中,可以用align-self

tooltip{
  right: anchor(left);
  align-self: anchor-center;
}

示意如下:

锚定居中 anchor-center

4. 更人性化的定位方式 inset-area

你可能在大部分组件库都用过类似这样的定位方式,例如Ant Design,一般是12个方位:

更人性化的定位方式 inset-area

是不是比较好理解?一看就懂,比前面的lefttop方式要简单的多了。

没错,锚点定位也支持类似的定位方式,引入了一种新型的定位系统叫做:inset-area

这个方式比前面的实现更加便捷、更加灵活,它将锚定元素分成九宫格,并且考虑了各个位置的可扩展性,一共有 20 种可能组合,如下:

inset-area: top; /* 居上,无尺寸限制 */
inset-area: top center; /* 居上并且不超过锚定元素尺寸 */
inset-area: top span-left;  /* 居上并且左边可以扩展 */
inset-area: top span-right;  /* 居上并且右边可以扩展 */
inset-area: left;
inset-area: left center;
inset-area: left span-top;
inset-area: left span-bottom;
inset-area: bottom center;
inset-area: bottom span-left;
inset-area: bottom span-right;
inset-area: bottom;
inset-area: right center;
inset-area: right span-top;
inset-area: right span-bottom;
inset-area: right;
inset-area: top left; /* 左上角 */
inset-area: top right; /* 右上角 */
inset-area: bottom left; /* 右下角 */
inset-area: bottom right; /* 右下角 */

看着是不是有点太多了,也有点晕,其实这里多了 8 种不常用的,下面做了一个示意图,可以很清楚的看到每种方位的具体位置(虚线部分就是常见的 12 种方位)

更人性化的定位方式 inset-area

以上截图修改来源于:anchor-tool

回到前面第一章的例子,要实现居上垂直居中,其实可以一行代码搞定:

tooltip{
  inset-area: top;
}

是不是又精简了许多呢?

5. 锚点尺寸 anchor-size

有时候,我们可能还需要知道锚定元素的尺寸,比如这样的场景:

锚点尺寸 anchor-size

可以看到,在切换tab时,底下的背景是可以无缝过渡的。在以前,我们要实现这样的功能,必须要借助 JS来获取当前点击元素的尺寸和位置,但现在,只需要借助 CSS 锚点定位就能轻松实现了。

位置信息前面以及提到了,用anchor(left)anchor(top)就可以了,那尺寸呢,需要用到anchor-size

anchor-size(width) /*锚点元素宽度*/
anchor-size(height)  /*锚点元素高度*/

利用这个特性,我们可以很轻松的实现这样一个效果,结构如下:

<nav class="tab">
  <a class="item" href="#HTML" name="HTML">HTML</a>
  <a class="item" href="#CSS" name="CSS">CSS</a>
  <a class="item" href="#JavaScript" name="JavaScript">JavaScript</a>
  <a class="item" href="#React" name="React">React</a>
  <a class="item" href="#Vue" name="Vue">Vue</a>
</nav>

我们用伪元素来当做tab高亮背景,关键实现如下:

.tab::after{
  content: '';
  position: absolute;
  border-radius: 100px;
  background-color: rgba(65, 105, 225, 0.2);
  position-anchor: --anchor-el;
  width: anchor-size(width);
  height: anchor-size(height);
  left: anchor(left);
  top: anchor(top);
  transition: .3s;
  pointer-events: none;
}
.item:target{
  anchor-name: --anchor-el;
}

这样就能轻松实现这个效果了。

完整代码:

.item{
  border: 0;
  font-size: 24px;
  border-radius: 100px;
  padding: 10px 24px;
  color: royalblue;
  background: none;
  overflow: hidden;
  cursor: pointer;
  transition: .2s;
  text-decoration: none;
}
.tab::after{
  content: '';
  position: absolute;
  border-radius: 100px;
  background-color: rgba(65, 105, 225, 0.2);
  position-anchor: --anchor-el;
  width: anchor-size(width);
  height: anchor-size(height);
  left: anchor(left);
  top: anchor(top);
  transition: .3s;
  pointer-events: none;
}
.item:target{
  anchor-name: --anchor-el;
}

6. 动态调整位置 position-try-options

有时候定位元素会处于屏幕边缘,当没有足够空间显示时,可以通过position-try-options来设置一个备用位置。

举个例子,比如一个气泡,默认是朝上的,当滚动到屏幕边缘时会自动朝下,示意如下:

动态调整位置 position-try-options

这种情况就可以用@position-try来实现了,具体做法是这样的。

先通过position-try-options指定一个变量名,比如--bottom

tooltip{
    position: fixed;
    position-anchor: --anchor-el;
    inset-area: top;
    position-try-options: --bottom;
}

然后通过@position-try来定义规则:

@position-try --bottom {
  inset-area: bottom;
}

这样就实现定位元素位置自动调整了。

除此之外,还有一种便捷写法,直接给position-try-options指定以下关键字:

position-try-options: flip-block; /*垂直翻转*/
position-try-options: flip-inline; /*水平翻转*/

这样就无需@position-try定义了,实现更简单。

完整代码:

<div class="space"></div>
<button>button</button>
<div class="space"></div>
<tooltip id="t1" >我是 tooltip</tooltip>
html {
  font-family: -apple-system, "BlinkMacSystemFont", sans-serif;
  margin: 0;
  height: 100%;
}
body{
  font-family: -apple-system, "BlinkMacSystemFont", sans-serif;
  margin: 0;
  height: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  background: aliceblue;
  gap: 10px;
}
button{
  border: 0;
  font-size: 24px;
  border-radius: 8px;
  padding: 10px 24px;
  color: royalblue;
  background: none;
  overflow: hidden;
  text-transform: uppercase;
  background-color: rgba(from royalblue r g b/.2);
  cursor: pointer;
  transition: .2s;
  flex-shrink: 0;
  anchor-name: --anchor-el;
  margin: 20px;
}
tooltip{
  position: fixed;
  position-anchor: --anchor-el;
  /* bottom: anchor( --anchor-el top); */
  /* justify-self: anchor-center; */
  inset-area: top;
  position-try-options: --bottom;
  padding: 10px;
  background-color: #333;
  color: #f0f0f0;
  text-align: center;
  border-radius: 4px;
  margin: 0 5px 5px 5px;
  box-shadow: 0 2px 6px rgba(0, 0, 0, 0.25);
  font-size: 14px;
  filter: drop-shadow(4px 4px 4px rgba(50, 50, 50, 0.3));
  transition: .2s;
  border: 0;
  overflow: visible;
}
@position-try --bottom {
  inset-area: bottom;
}
.space{
  width: 300px;
  height: 880px;
  background-color: antiquewhite;
  flex-shrink: 0;
}
.list{
  position: relative;
  height: 400px;
  width: 500px;
  overflow: auto;
  outline: 3px dashed rebeccapurple;
}

当然,我觉得这个功能还是稍显不足的,比如当气泡带有箭头时,虽然也能翻转,但是却无法改变箭头的位置,也就是无法查询到当前是否已经翻转了,就像这样:

css 锚点定位不足之处

希望尽快解决吧~

三、和 popover 配合使用

早在之前介绍popover的时候,就已经在期待这个功能了。

毕竟popover只是解决了层级的问题,而锚点定位解决了定位问题。两者结合,我们可以很轻松的实现各种常见的效果,已经可以说能够完全替代主流框架中的popover组件了。

下面是一个功能完善的多级菜单,完全无需 JS即可实现:

多级菜单

首先是点击出现,这个就是popover的功能了,通过popovertargetpopover属性,将两者结合起来,就能轻松实现点击出现菜单的功能。

<button class="btn" popovertarget="more"></button>
<div class="menu" id="more" popover>
  <button class="item">编辑</button>
  <button class="item">删除</button>
</div>

然后就定位,利用CSS锚点定位,将菜单定位到按钮的右下方,也就两三行代码的事:

.btn{
  anchor-name: --menu;
}
.menu{
  position-anchor: --menu;
  inset-area: bottom span-right;
}

样就能轻易实现悬浮菜单了。

完整代码:

<button class="btn" popovertarget="more" style="position-anchor: --menu;"></button>
<div class="menu" id="more" popover style="position-anchor: --menu; inset-area: bottom span-right;">
  <button class="item">编辑</button>
  <button class="item">删除</button>
  <button class="item" hidden popovertarget="other" style="anchor-name: --other">其他 →</button>
  <div class="menu" id="other" popover style="position-anchor: --other; inset-area: right span-bottom">
    <button class="item">还原</button>
    <button class="item">保存</button>
  </div>
</div>
html,body{
  font-family: -apple-system, "BlinkMacSystemFont", sans-serif;
  margin: 0;
  height: 100%;
  display: flex;
  justify-content: center;
  align-items: center;
  background: aliceblue;
  gap: 10px;
}
.btn{
  border: 0;
  width: 40px;
  height: 40px;
  border-radius: 4px;
  anchor-name: --menu;
  background: url("data:image/svg+xml,%3Csvg width='32' height='32' viewBox='0 0 32 32' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M9 14.25a1.75 1.75 0 1 1 0 3.5 1.75 1.75 0 0 1 0-3.5zm7 0a1.75 1.75 0 1 1 0 3.5 1.75 1.75 0 0 1 0-3.5zM24.75 16a1.75 1.75 0 1 0-3.5 0 1.75 1.75 0 0 0 3.5 0z' fill='%23191919'/%3E%3C/svg%3E") center;
}
button:hover{
  background-color: rgba(65, 105, 225, 0.2);
}
.menu{
  position-anchor: --menu;
  inset-area: bottom span-right;
  background-color: #fff;
  box-shadow: 0 2px 6px rgba(0, 0, 0, 0.25);
  border-radius: 4px;
  border: 0;
  margin: 0;
}
.item{
  display: block;
  width: -webkit-fill-available;
  text-align: left;
  border: 0;
  padding: 2px 10px;
  background-color: transparent;
  font-size: 14px;
  border-radius: 4px;
}

四、总结

介绍了这么多,大家一下子肯定难以接受,多回顾几遍就明白了,至少可以知道锚点定位是干嘛的,如果以后有类似的需求也有一定的方向,下面总结一下本文要点

  1. CSS 锚点定位是一个颠覆性的新特性,一定要学会
  2. CSS 锚点定位可以设置任意元素相对任意元素做定位
  3. 主要是通过anchor-nameposition-anchor两个属性关联
  4. 锚点的位置用anchor()来定义,比如anchor(left)表示锚定元素的最左侧,anchor(top)表示锚定元素的最上侧
  5. anchor-center可以实现居中定位,水平居中justify-self: anchor-center,垂直居中align-self: anchor-center
  6. inset-area是一种更人性化的定位方式,和常见的组件库表示方位比较类似
  7. 还可以通过 anchor-size来锚点元素的尺寸,anchor-size(width)表示宽度,anchor-size(height)表示高度
  8. position-try-options可以根据定位元素是否处于屏幕边缘而自适应定位方向
  9. 实际中更推荐和popover相互配合,可以轻松实现各类悬浮层效果
  10. 兼容性要求 Chrome 125+,期待早日使用吧

最近几年CSS更新的确实有点太快了,很多以往的疑难杂症都有了新的解决方式。但是很多时候学这些好像暂时没啥用,毕竟可能 5 年以后才用得上。但是原生特性不像其他,一个框架两三年就有可能被淘汰,或者有新的替代品出现,原生的学到了就学到了,只要web存在的一天,就永远都不会过时,所以也不亏是吧。

以上关于CSS anchor锚点定位:让你的网页精准导航的文章就介绍到这了,更多相关内容请搜索码云笔记以前的文章或继续浏览下面的相关文章,希望大家以后多多支持码云笔记。

「点点赞赏,手留余香」

0

给作者打赏,鼓励TA抓紧创作!

微信微信 支付宝支付宝

还没有人赞赏,快来当第一个赞赏的人吧!

声明:本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若内容造成侵权/违法违规/事实不符,请将相关资料发送至 admin@mybj123.com 进行投诉反馈,一经查实,立即处理!
重要:如软件存在付费、会员、充值等,均属软件开发者或所属公司行为,与本站无关,网友需自行判断
码云笔记 » CSS anchor锚点定位:让你的网页精准导航

发表回复