O Problema das Animações Escalonadas (e de Tudo Mais)
Sabe aquela sensação: você tem uma grade de cards, uma lista de itens, um conjunto de abas. Quer que eles apareçam um após o outro, ou se distribuam igualmente, ou formem um círculo. Toda vez, você acaba escrevendo uma dúzia de regras :nth-child() ou fazendo um loop em JavaScript para definir variáveis --index inline.
/* O jeito antigo: uma regra por item */
li:nth-child(1) { --idx: 1; }
li:nth-child(2) { --idx: 2; }
/* ... mais nove ... */
li {
animation-delay: calc(var(--idx) * 100ms);
}
Dez itens, dez regras. Cinquenta itens? Ou você limita ou gera centenas de seletores no build. JavaScript funciona, mas espalha preocupações de layout pelos seus scripts e quebra silenciosamente quando alguém refatora o componente.
O navegador já sabe qual elemento é o terceiro filho. Ele construiu a árvore DOM. O CSS só não conseguia acessar essa informação — até agora.
Baseado no artigo original do Smashing Magazine, aqui está tudo que você precisa saber sobre as novas funções CSS de contagem de irmãos.

Como sibling-index() e sibling-count() Funcionam
sibling-index() retorna a posição (base 1) de um elemento entre os filhos do seu pai. Primeiro filho retorna 1, quinto filho retorna 5. sibling-count() retorna o número total de filhos elemento que o pai possui.
Ambas as funções resolvem para um número real, não uma string. Isso significa que você pode usá-las em calc(), min(), max(), round() e até funções trigonométricas como sin() e cos().
/* Animação escalonada em uma linha */
li {
animation-delay: calc(sibling-index() * 100ms);
}
/* Escalonamento reverso: último item anima primeiro */
.card {
animation: fade-in 0.4s ease both;
animation-delay: calc((sibling-count() - sibling-index()) * 80ms);
}
/* Larguras iguais automáticas */
.tab {
width: calc(100% / sibling-count());
}
Isso é fundamentalmente diferente de :nth-child(), que é um seletor. :nth-child() seleciona elementos — não produz um valor para você calcular. sibling-index() fica dentro das suas declarações e te dá um número. Eles resolvem problemas diferentes.

Padrões Práticos e Armadilhas
Menus Circulares
.radial-item {
--angle: calc((360deg / sibling-count()) * sibling-index());
--radius: 120px;
position: absolute;
left: calc(50% + var(--radius) * cos(var(--angle)));
top: calc(50% + var(--radius) * sin(var(--angle)));
transform: rotate(calc(var(--angle) * -1));
}
Seis itens? Hexágono. Oito? Octógono. Adicione ou remova itens e o layout recalcula. Sem JavaScript calculando coordenadas.
Distribuição de Matiz
.swatch {
background-color: hsl(
calc((360deg / sibling-count()) * sibling-index()) 70% 50%
);
}
Três itens recebem matizes separados por 120°. Doze itens recebem incrementos de 30°. A paleta se adapta ao que está no DOM.
As Armadilhas que Você Precisa Conhecer
- Escopo do Shadow DOM: Essas funções operam na árvore DOM, não na árvore visual achatada. Dentro de uma shadow root, elas só veem os filhos da árvore shadow. Conteúdo projetado via
<slot>é invisível. display: noneainda conta: Elementos ocultos ainda estão no DOM, entãosibling-index()os inclui. Para filtros de busca ou visibilidade dinâmica, você precisa remover os nós ou usar JavaScript.- Pseudo-elementos não contam:
::beforee::afternão são irmãos. Mas você pode usar essas funções dentro de declarações de pseudo-elementos — elas avaliam contra o elemento de origem. - Propriedades personalizadas avaliam imediatamente: Se você definir
--idx: sibling-index()em um pai, ele resolve para o índice do pai. Cada filho herda esse único valor fixo. Aplique a função diretamente nos elementos que precisam dela.

Suporte e Aprimoramento Progressivo
Em meados de 2025, Chrome/Edge 138 e Safari 26.2 já enviam essas funções. O Firefox está trabalhando nisso (rastreado no Bugzilla #1953973). Chrome e Safari juntos cobrem cerca de 75-80% do tráfego global.
Para produção hoje, use @supports:
/* Base: funciona em todo lugar */
.item {
width: 25%;
animation-delay: 0ms;
}
/* Aprimoramento progressivo */
@supports (z-index: sibling-index()) {
.item {
width: calc(100% / sibling-count());
animation-delay: calc(sibling-index() * 80ms);
}
}
Performance em Escala
Alterar o DOM dispara recálculo de estilo para os irmãos afetados. Para UI normal (navs, grids, abas), você nunca vai notar. Mas para um feed de scroll infinito com milhares de nós mudando constantemente, continue usando índices gerenciados por JavaScript dentro da sua janela de virtualização.
O Que Está Por Vir
O CSSWG discutiu um argumento of (como :nth-child() já suporta) para contar apenas irmãos que correspondem a um seletor específico. Também há conversas sobre funções children-count() e descendant-count() para layouts orientados pelo pai.
Nota de Acessibilidade
Essas funções são puramente visuais. Se você usar sibling-index() para reordenar visualmente uma lista, um leitor de tela ainda lê o DOM na ordem de origem. Para componentes interativos, você ainda precisa de JavaScript para sincronizar atributos ARIA (aria-posinset, aria-setsize).
Limitações e Cuidados
- Sem suporte no Firefox ainda: Você precisa de um fallback para ~20% dos usuários.
display: nonequebra a contagem sequencial: Para menus radiais ou larguras proporcionais com filtragem dinâmica, considere remover nós do DOM em vez de escondê-los.- Isolamento do Shadow DOM: Autores de web components precisam estar cientes das limitações de escopo.
Próximos Passos
- Teste essas funções no Chrome Canary ou Safari Technology Preview
- Comece com aprimoramento progressivo protegido por
@supportsem projetos secundários - Leia a especificação CSS Values and Units Module Level 5 para detalhes completos
- Explore padrões relacionados como CSS em escala com StyleX para uma abordagem diferente de estilos sustentáveis
Leitura complementar: Para um mergulho mais profundo na minimização de custos de runtime em IA de jogos, confira nossa análise sobre agentes de código vs chamada de ferramentas.