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.

Developer writing CSS with sibling-index function for staggered animation layout on laptop Algorithm Concept Visual

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.

CSS code editor showing sibling-count and calc for automatic equal width tabs Development Concept Image

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: none ainda conta: Elementos ocultos ainda estão no DOM, então sibling-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: ::before e ::after nã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.

Desktop setup with multiple monitors displaying CSS grid and radial menu using sibling-index Developer Related Image

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: none quebra 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

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.

Este conteúdo foi elaborado com o auxílio de ferramentas de IA, com base em fontes confiáveis, e revisado pela nossa equipe editorial antes da publicação. Não substitui o aconselhamento de um profissional especializado.