CSS锚点定位终于来了!

开发 前端
最近 ​​Chrome 125​​​终于迎来了​​CSS​​ 锚点定位的正式支持。这是一个和 ​​CSS​​ 滚动驱动动画一样,足以颠覆整个 ​​Web​​ 开发领域的新特性。有了这个特性,很多以前强依赖​​ JS​​ 的方式,都可以纯 ​​CSS​​解决,并且实现起来更加简单、更加灵活,一起看看吧

盼了好久,最近 Chrome 125终于迎来了CSS 锚点定位的正式支持。这是一个和 CSS 滚动驱动动画一样,足以颠覆整个 Web 开发领域的新特性。有了这个特性,很多以前强依赖 JS 的方式,都可以纯 CSS解决,并且实现起来更加简单、更加灵活,一起看看吧!

一、快速了解 CSS 锚点定位

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

如果不借助 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-name和position-anchor将两个元素关联(锚定)起来,如下:

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

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

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

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

你也可以访问以下在线链接(Chrome 125+)

  • CSS anchor (codepen.io)[1]

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

二、CSS 锚点定位语法详解

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

3. 锚定居中 anchor-center

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

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

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

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

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

示意如下:

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

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

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

没错,锚点定位也支持类似的定位方式,引入了一种新型的定位系统叫做: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种方位)。

以上截图修改来源于:https://anchor-tool.com。

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

tooltip{
  inset-area: top;
}

是不是又精简了许多呢?

5. 锚点尺寸 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;
}

这样就能轻松实现这个效果了,你也可以访问以下在线链接(Chrome 125+)

  • CSS anchor nav (codepen.io)[2]


6. 动态调整位置 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定义了,实现更简单。

  • CSS anchor position-try-options (codepen.io)[3]

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

希望尽快解决吧~

三、和 popover 配合使用

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

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

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

<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;
}

这样就能轻易实现悬浮菜单了,你也可以访问以下在线链接(Chrome 125+)

  • CSS anchor menu (codepen.io)[4]

在codepen上找到了一个更完善的多级菜单案例。

https://codepen.io/jh3y/pen/dyLjbwG

四、总结和其他

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

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

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

[1]CSS anchor (codepen.io): https://codepen.io/xboxyan/pen/dyEVVPb。

[2]CSS anchor nav (codepen.io): https://codepen.io/xboxyan/pen/zYQpvqg。

[3]CSS anchor position-try-options (codepen.io): https://codepen.io/xboxyan/pen/dyEJYRO。

[4]CSS anchor menu (codepen.io): https://codepen.io/xboxyan/pen/qBGpOKq。

责任编辑:姜华 来源: 前端侦探
相关推荐

2023-02-13 09:31:07

CSS前端

2024-05-23 10:34:15

CSS 3CSS技术

2022-09-29 12:20:48

CSS容器查询

2023-05-29 08:38:56

popover控制悬浮层

2017-04-17 09:01:39

科技新闻早报

2013-07-12 09:59:58

Android 5.0

2009-10-22 08:50:33

Windows 7上市新闻

2021-04-20 08:03:26

单播协议TCP

2024-08-15 11:37:05

2009-10-19 14:15:24

TreeView节点定

2013-08-28 10:27:14

腾讯云百度云

2021-10-22 15:45:32

开发技能React

2010-08-25 15:56:10

CSSPositioning定位

2019-05-14 09:00:54

Linux 系统 数据

2024-01-30 00:09:29

iOS 17.3苹果

2023-10-25 16:06:29

iOS 18ChatGPT

2024-04-28 09:01:06

React 19更新前端

2024-04-03 14:53:05

iOS 17.5侧载

2023-03-03 07:34:05

2010-09-06 11:17:19

CSS相对定位CSS绝对定位
点赞
收藏

51CTO技术栈公众号