sibling-index() と sibling-count():CSS がついに自分が何番目かを知る

Firefox 154 がこの二つの関数を Baseline に押し上げた。兄弟の中での位置と兄弟の総数を返すので、時間差アニメーション、順序に応じた配色、均等割りまで 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 になる

前者は「三番目を赤くする」と言えます。後者は「N 番目の遅延は N × 60ms」と言えます。後者は以前、JavaScript かインライン変数が必要でした。

対応状況

ブラウザ バージョン
Chrome / Edge 138
Firefox 154
Safari 26.2

三家とも到達したので Baseline Newly available です。つまり「使えるが古いブラウザでは退行する」。この二つの関数は見た目(遅延、配色、幅)にしか影響しないので、退行の結果は「全部同時に出る/同色/等幅」であり、レイアウトが壊れたりエラーになったりはしません。安心して漸進的強化として使える類です。

私の結論

多くの行数を節約するものではありません。消えるのは長らく慣習で維持されてきた結合の一種です。

「この要素が何番目か」は DOM の内在的な性質なのに、ビルドツールやテンプレート変数で外から注入しなければなりませんでした。注入とは同じ事実を二か所が知っているということで、二か所は必ずずれます。要素を足して --i を直し忘れるのが典型症状です。

今は数が DOM から直接読めます。真実は一つです。外部の取り決めを内部への問い合わせに変える変更は、節約した行数よりも、消したバグの原因のほうに価値があります。

← 記事一覧に戻る

コメント

…