你以为 CSS 只能选元素、不能计数?今天两个函数把这件事彻底原生化了
写过 CSS 的人都踩过这个坑——给列表写交错动画,要么写一整屏 nth-child 规则、要么开 Sass 循环硬编码数量、要么写一段 JS 跑 DOM 再塞回内联样式。改一个 item 整份代码都得动,加一个卡片的代价是把手写规则全改一遍。
CSS 过去从来不告诉你「自己在第几个」,只告诉你「自己是不是第 N 个」。这个缺口从 CSS 诞生起就存在了。
两个函数闭这个坑。
sibling-index() 返回元素在自己 siblings 中的位置,从 1 开始。sibling-count() 返回同父级下 siblings 的总数。两者都是整数,可以直接扔进 calc() 参与运算。
最直接的用法:
.card {
animation: card-in 400ms ease both;
animation-delay: calc((sibling-index() – 1) * 120ms);
}
@keyframes card-in {
from { opacity: 0; transform: translateY(20px); }
to { opacity: 1; transform: translateY(0); }
}
一行声明,列表有 5 张卡还是 50 张卡浏览器自己算。
这里减 1 很关键:sibling-index() 从 1 开始,不减的话第一张卡要等整整一个 120ms 才动。
同样原理,等宽网格:
.item {
width: calc(100% / sibling-count());
}
七张卡片自动分七等分,加一张服务器直出塞进去,宽度自己重新算,不需要改一行 CSS。
再看一个进阶用法,七张卡片从左到右颜色渐变:
.card {
background: hsl(calc(sibling-index() * 360 / sibling-count()), 70%, 55%);
}
每张卡片的背景色由自己在列表中的位置决定,数量越多过渡越细腻,总色域始终覆盖完整 360 度色轮。
还有几个工程上要知道的细节:
sibling-index() 从 1 开始,不是从 0。这个是最容易踩的坑,不减 1 的话第一个元素永远是迟一拍的。
display: none 的元素依然会被计数。它们从视觉树和无障碍树里消失了,但还在 DOM 树里,所以 sibling-count() 依然会算进去。如果用 filter 隐藏元素做动态列表,渐变会出现「空洞」——此时只能物理移除 DOM 节点,或者换用 visibility: hidden(后者仍然计数)。
::before 和 ::after 不参与计数。它们不是真实 DOM 节点,sibling-count() 不会把伪元素算进去,但 sibling-index() 用在 ::before 里时会取其宿主元素的位置。
浏览器支持情况:Chrome 138+、Safari 26.2+、Edge 138+、Firefox 154+。Firefox 154 是 2026 年 8 月 18 日刚刚 stable,Chrome 和 Safari 则从 2025 年中就开始支持,四个主流浏览器合计覆盖全球约 92% 用户。CSS Values Level 5 规范正式纳入,属于 Baseline Newly Available。
渐进增强写法:
.item {
/ 默认:四个一行,Firefox 等旧浏览器走这里 /
width: 25%;
animation-delay: 0ms;
}
/ 支持的环境增强:浏览器自己算等宽和 stagger /
@supports (width: sibling-count(1)) {
.item {
width: calc(100% / sibling-count());
animation-delay: calc((sibling-index() – 1) * 80ms);
}
}
评论区
登录后可评论。