Дайджесты новостей
Передача счетчика дочерних элементов родителю в чистом CSS через Scroll-Driven Animations и расчет сетки функцией sqrt.

Передача sibling-count() родительскому элементу через CSS Scroll-Driven Animations

В современной спецификации CSS функции sibling-count() и sibling-index() открыли отличные возможности для адаптации компонентов. Дочерний элемент теперь может самостоятельно узнать, сколько у него соседей, и настроить оформление. Однако здесь верстальщики упираются в фундаментальное ограничение: CSS-каскад строго однонаправлен. Стили передаются сверху вниз — от предков к потомкам, но никогда обратно.

Родительский контейнер остается слеп к количеству собственных детей. Он не может получить числовую переменную с числом потомков, чтобы подставить ее в математические функции calc(), sqrt() или тригонометрические формулы. Официальное предложение children-count() пока находится на стадии ранних обсуждений в W3C.

Фронтенд-исследователь Темани Афиф (Temani Afif) нашел остроумный обходной путь. Он продемонстрировал, как анимации по шкале прокрутки (CSS Scroll-Driven Animations) позволяют «пробить» каскад снизу вверх и передать счетчик детей в числовую переменную --n на родителе без единой строчки JavaScript.

Механика трюка: фиктивный маркер и проброс через timeline-scope

В основе решения лежит связка трех механизмов:

  1. Маркер ширины: внутрь контейнера помещается служебный тег <n></n>. Его ширина рассчитывается через число соседей: width: calc((sibling-count() - 1) * 1px). Если в контейнере 16 карточек, ширина маркера составит ровно 16 пикселей.
  2. Экспорт шкалы времени (timeline-scope): маркер объявляет горизонтальную шкалу видимости view-timeline: --n x. Родительский блок указывает timeline-scope: --n, что поднимает область видимости шкалы на уровень родителя и позволяет привязать анимацию контейнера к геометрии потомка.
  3. Конвертация геометрии в число: на родителе запускается анимация переменной --n от 1000 до 0. Диапазон animation-range: exit calc(100% - 1000px) exit калибрует прогресс строго по ширине маркера в пикселях. В итоге переменная --n на контейнере получает точное целочисленное значение количества дочерних блоков.
<div class="container">
  <div class="card">Элемент 1</div>
  <div class="card">Элемент 2</div>
  <div class="card">Элемент 3</div>
  <div class="card">Элемент 4</div>
  <!-- Служебный маркер для передачи счетчика родителю -->
  <n></n>
</div>
/* Родительский контейнер */
.container {
  position: relative;
  overflow: hidden;

  /* Поднимаем область видимости шкалы времени маркера */
  timeline-scope: --n;
  animation: --n-anim linear both;
  animation-timeline: --n;
  animation-range: exit calc(100% - 1000px) exit;

  /* Динамическая адаптивная сетка на основе квадратного корня */
  display: grid;
  grid-template-columns: repeat(round(up, sqrt(var(--n))), 1fr);
  gap: 16px;
}

/* Служебный элемент-маркер */
.container > n {
  position: absolute;
  left: 0;
  width: calc((sibling-count() - 1) * 1px);
  view-timeline: --n x;
}

/* Анимация преобразует сдвиг границы в числовую переменную */
@keyframes --n-anim {
  0% { --n: 1000; }
  to { --n: 0; }
}

Адаптивные квадратные сетки на чистом CSS с помощью sqrt()

Получив переменную --n, контейнер обретает динамические возможности:

  • Выражение grid-template-columns: repeat(round(up, sqrt(var(--n))), 1fr) автоматически вычисляет число колонок.
  • Если в контейнере 9 элементов, сетка перестроится в 3x3. Если элементов 16 — в 4x4, а для 12 элементов раскладка примет вид 4x3. Все это происходит реактивно при изменении разметки без JavaScript и хрупких медиавыражений.

Значение --n можно использовать и для отображения счетчиков в интерфейсе:

/* Вывод общего числа элементов через CSS-счетчики */
.container::before {
  counter-reset: total-items var(--n);
  content: "Всего карточек в секции: " counter(total-items);
  grid-column: 1 / -1;
  font-weight: 600;
}

Границы применимости: смелый эксперимент против продакшен-стандартов

Инженеру важно помнить об ограничениях приема. Связка timeline-scope и sibling-count() стабильно работает только в браузерах на Chromium (Google Chrome и Microsoft Edge 125+), а в Safari и Firefox находится в разработке.

Кроме того, метод требует position: relative и overflow: hidden. В продакшене до стандартизации children-count() надежнее использовать строку JS (container.childElementCount). Тем не менее эксперимент Темани Афифа доказывает: возможности современной веб-платформы выходят далеко за привычные рамки верстки.