sibling-index() 和 sibling-count():CSS 终于知道自己是第几个

Firefox 154 让这两个函数进入 Baseline。它们返回当前元素在兄弟中的序号和兄弟总数,于是错落动画、按序配色、均分尺寸都能在 CSS 里算完,不必再给每个元素挂一个内联样式或 CSS 变量。

Firefox 154 支持了 sibling-index() 与 sibling-count(),两个函数就此进入 Baseline Newly available。

它们做的事很小:

  • sibling-index() 返回当前元素在兄弟节点中的位置,从 1 开始
  • sibling-count() 返回父容器里兄弟 DOM 元素的总数(包含元素自己)

但这两个数字以前只能从 JavaScript 拿。

以前怎么做的

想做一个「每个卡片依次延迟出现」的效果,标准写法是:

<li style="--i: 0">…</li>
<li style="--i: 1">…</li>
<li style="--i: 2">…</li>
li {
  animation-delay: calc(var(--i) * 60ms);
}

于是每加一个元素就要手写一次 --i,漏一个就整个序列错位。模板语言里要写循环变量,静态站点里要小心别让构建产物和源文件不同步。

现在可以删掉那行内联样式:

li {
  animation-delay: calc((sibling-index() - 1) * 60ms);
}

从 1 开始这点要留意 —— 想要「第一个不延迟」就得减 1,忘了就会出现第一个元素先等 60ms 的轻微顿挫。

三个真正有用的场景

错落动画

上面那个。加元素不用再动样式,顺序天然跟着 DOM 走。

按序号配色

色相环上均匀铺开:

.swatch {
  background: hsl(calc(sibling-index() * 360deg / sibling-count()) 70% 55%);
}

改元素数量时配色自动重算,不需要维护一份调色板变量。

均分可用空间

sibling-count() 让「我不知道有几个」这件事不再是障碍:

.bar {
  width: calc(100% / sibling-count());
}

当然 flex / grid 在多数情况下更合适 —— 这个用法真正有价值的地方是不能用 flex 的场合(绝对定位、或者需要显式算宽度的时候)。

和已有的选择器什么关系

CSS 里本来就有 :nth-child()、:first-child、:last-child 这些。区别在于:

  • :nth-child(3) 是选择器 —— 它只能决定「哪条规则命中哪个元素」,命中了才能改样式
  • sibling-index() 是值 —— 它返回一个数字,可以参与 calc()、可以进 hsl()、可以当 animation-delay

前者能表达「第 3 个变红」,后者能表达「第 N 个的延迟是 N × 60ms」。后者以前必须用 JS 或内联变量。

支持情况

浏览器 版本
Chrome / Edge 138
Firefox 154
Safari 26.2

三家都到齐了,所以是 Baseline Newly available —— 意思是「能用,但旧版本浏览器上会退化」。因为这两个函数只影响观感(延迟、配色、宽度),退化后的结果是「所有元素同时出现 / 同色 / 等宽」,不会坏掉布局或报错,属于可以放心渐进增强的那一类。

我的判断

这两个函数不会让你少写多少代码,但它们消掉了一类长期靠约定维持的耦合:

「这个元素的序号」本来是 DOM 的固有属性,却要靠构建工具或模板变量从外面注入进去。注入意味着有两个地方知道同一件事,而两处知识迟早会不同步 —— 加了一个元素忘了改 --i,就是最典型的症状。

现在数字从 DOM 里直接读,只有一个真相。这类「把已有事实从外部约定变成内部查询」的改动,价值往往不在省下的那几行,而在于删掉了一类 bug 的成因。

← 返回文章列表

评论

…