Anchor 初体验:实现一个可追随的 Navbar 滑块
我在 blog 上一个 theme 折腾导航栏的时候,为了实现那个“滑块跟随鼠标”的效果,跟 CSS 里的 nth-child 还有 translateX 较劲了半天。
偏移百分比和像素是手动调式出来的。要是按钮里的文字长短不一,那简直灾难。
手算偏移量
这是我以前最常用的办法。给导航栏加个伪元素当背景,然后鼠标指到哪个,就手动把背景“挪”过去。当然这类效果用 JS 其实更好实现,但个人的强迫症,我是不会在导航上引入 JS 的。
代码写起来大概长这样:
.navbar::before {
width: 60px;
transition: transform 0.3s;
}
.navbar:has(a:nth-child(1):hover)::before { transform: translateX(0); }
.navbar:has(a:nth-child(2):hover)::before { transform: translateX(64px); }
每增加一个导航链接,就得去重新算一遍偏移量。之前导航还有图标 + 响应式设计,手机上没图标就露馅了,为了动效把图标砍了。
Anchor
用上 Anchor Positioning 之后,逻辑变得非常简洁。滑块只需要通过声明式语言指定它的锚点目标即可。
这种方式让定位逻辑回归到了最直觉的状态:你只需要声明“要跟谁对齐”,剩下的适配工作交给浏览器原生处理。
比如下面 .indicator 声明了 position-anchor: --nav-anchor
<nav class="navbar">
<a class="active">首页</a>
<a class="px-6">超长字段的友链</a>
<a>关于</a>
<div class="indicator"></div>
</nav>
<style>
.active { anchor-name: --nav-anchor; }
a:hover { anchor-name: --nav-anchor; }
/* 当有任意一个链接被 hover 但不是 .active,.active 就暂时失去锚点名 */
:has(a:hover:not(.active)) .active { anchor-name: none; }
.indicator {
position: absolute;
position-anchor: --nav-anchor;
left: anchor(left);
right: anchor(right);
top: anchor(top);
bottom: anchor(bottom);
transition: all 0.3s ease;
}
</style>
按钮里的文字不管多长,anchor(right) 都能精准映射到边缘,滑块也因此实现了自动适配。
总结
在以往的方案中,依赖 JavaScript 监听尺寸变化,而现在,我们可以直接使用声明式语言定义元素间的逻辑关联,将复杂的坐标计算交给浏览器的渲染引擎处理。
浏览器支持
最新浏览器已经基本支持了,Firefox 似乎还有点问题。
本作品采用知识共享署名-非商业性使用-相同方式共享 (CC BY-NC-SA) 协议进行许可。