В августе CSS получил сведения о положении элемента среди соседей, а декларативный теневой DOM стал широко доступным. Разберём список с задержками анимации, изолированный бейдж и новый способ соединять значения итератора в строку.

Темы взяли из августовского выпуска Web Features Explorer. Факты сверены на 9 октября 2026 года. Newly Available означает поддержку актуальных основных браузеров; Widely Available наступает спустя 30 месяцев. В старых версиях и встроенных браузерах приложений поддержка может отличаться.

Что получили актуальные браузеры

sibling-index() и sibling-count(): порядок элементов в вычислениях CSS

Чтобы элементы списка появлялись по очереди, раньше можно было назначать каждому отдельную задержку. Функция sibling-index() возвращает номер элемента среди соседних элементов: первый получает один, следующий — два. Номер можно сразу подставить в calc().

18 августа функции sibling-index() и sibling-count() стали Newly Available после выхода Firefox 154. Карточка поддержки в Explorer.

В примере четыре этапа заказа. Все остаются пунктами одного списка; CSS добавляет короткую декоративную анимацию, не меняя порядок чтения.

<ol class="steps">
  <li>Выбор товара</li>
  <li>Контакты</li>
  <li>Доставка</li>
  <li>Подтверждение</li>
</ol>
.steps > li {
  padding: 0.5rem;
  margin-block: 0.5rem;
  background: #eee9ff;
}

@keyframes arrive {
  from { transform: translateY(8px); }
  to { transform: translateY(0); }
}

@supports (animation-delay: calc(sibling-index() * 1ms)) {
  @media (prefers-reduced-motion: no-preference) {
    .steps > li {
      animation: arrive 200ms ease-out;
      animation-delay: calc((sibling-index() - 1) * 80ms);
    }
  }
}

Текст виден сразу. Первый пункт начинает движение без задержки, четвёртый — через 240ms. Если браузер не понимает функцию или пользователь просит уменьшить движение, останется обычный список.

sibling-count() возвращает общее число дочерних элементов родителя, включая текущий. Например, значение calc(1 / sibling-count()) даст долю одного элемента в группе. Сама функция не распределяет пространство: для обычных равных колонок мы рекомендуем сначала проверить Flexbox или Grid Layout.

Обе функции считают все соседние элементы, независимо от класса и видимости. Если добавить под тот же родитель заголовок, номера пунктов сдвинутся; если скрыть пункт через display: none, он останется в подсчёте. Текстовые узлы в расчёт не входят. Селектор .steps > li ограничивает применение правила, но не задаёт фильтр для счётчика. sibling-index на MDN, sibling-count на MDN.

Что стало широко доступным

Декларативный теневой DOM: бейдж со своими стилями

20 августа декларативный теневой DOM перешёл в Widely Available. Атрибут shadowrootmode у template создаёт отдельное DOM-поддерево внутри родительского элемента прямо при разборе HTML. Для этого шага JavaScript не требуется. Карточка декларативного теневого DOM в Explorer.

Сохраните пример в HTML-файл и откройте его браузером. На странице будут два бейджа: внешний со светло-серым фоном и внутренний с фиолетовым.

<!doctype html>
<html lang="ru">
  <meta charset="utf-8">
  <title>Бейдж с теневым DOM</title>
  <style>
    .badge { padding: 0.4rem; background: #eee; }
  </style>
  <body>
    <p><span class="badge">Обычный бейдж</span></p>

    <div class="product-label">
      <template shadowrootmode="open">
        <style>
          :host { display: inline-block; }
          .badge {
            padding: 0.4rem 0.7rem;
            border-radius: 0.5rem;
            background: #4e3295;
            color: white;
          }
        </style>
        <span class="badge"><slot></slot></span>
      </template>
      <span>Новинка</span>
    </div>
  </body>
</html>

Надпись живёт снаружи. slot выводит текст «Новинка» из обычного содержимого родителя. Внутри template находятся локальные стили и оболочка бейджа. Если декларативный теневой DOM недоступен, содержимое шаблона останется скрытым, но надпись снаружи template сохранится.

Стили разделились. Внешнее правило .badge не выбирает внутреннюю оболочку в теневом DOM. При этом наследуемые свойства, например шрифт, могут приходить от родителя. Изоляция стилей не означает, что компонент перестаёт зависеть от окружения.

Пример рассчитан на исходный HTML документа. Если присвоить такую строку свойству innerHTML, декларативный теневой корень не создастся. Для динамической вставки нужны специально предназначенные API или создание корня через attachShadow(); это отдельный сценарий. Атрибут shadowrootmode на MDN, ограничение innerHTML на MDN.

Теневой DOM не служит границей безопасности и по умолчанию не скрывает содержимое от вспомогательных технологий. Сохраняйте семантику внутренних элементов и проверяйте чтение компонента. Здесь бейдж — текст; если вместо него появится кнопка, понадобится проверить клавиатуру и видимость фокуса. Границы изоляции теневого DOM на MDN.

Что пробовать с запасным вариантом

Iterator.join(): собрать строку из последовательности

В августе Firefox 154 добавил Iterator.prototype.join(). На 9 октября метод также доступен в Chrome и Edge, но Safari его не поддерживает. У возможности остаётся ограниченная доступность. Карточка Iterator.join в Explorer.

Метод читает значения итератора до конца и соединяет их заданным разделителем. Для массива привычный Array.prototype.join() сохраняется. Новинка полезна, когда у вас уже есть итератор, например результат вызова Set.prototype.values().

const tags = new Set(['HTML', 'CSS', 'JavaScript']);
const iterator = tags.values();

const label = typeof iterator.join === 'function'
  ? iterator.join(' · ')
  : Array.from(iterator).join(' · ');

console.log(label);
// HTML · CSS · JavaScript

Проверка выбирает ровно одну ветку. Ветка с Array.from() сначала создаёт массив, затем соединяет его элементы. Новый метод ей не нужен. Правила преобразования значений описаны в предложении Iterator Join от TC39.

После соединения одноразовый итератор исчерпан. Для нового прохода получите свежий итератор из исходного набора:

const secondLabel = Array.from(tags.values()).join(', ');
console.log(secondLabel);
// HTML, CSS, JavaScript

Вызывать запасной вариант после iterator.join() на той же переменной нельзя: значений там уже не осталось. У бесконечного итератора соединение вообще не завершится.

Что попробовать в своём проекте

Начните со списка этапов: здесь новое правило улучшает оформление, а смысл сохраняется при отсутствии поддержки. Для теневого DOM выберите небольшой самостоятельный компонент, который можно проверить целиком.

  • Сопоставьте порядок элементов в HTML и задержки анимации.
  • Проверьте список с настройкой уменьшения движения.
  • Откройте пример бейджа как отдельный HTML-документ и убедитесь, что надпись видна.
  • Запустите ветку соединения через массив с новым итератором.

Два вопроса для проверки: что произойдёт с задержками, если рядом с пунктами появится ещё один элемент, и откуда возьмётся надпись «Новинка» в браузере без декларативного теневого DOM? Попробуйте эти изменения в примере до переноса в рабочий компонент.


«Доктайп» — журнал о фронтенде. Читайте, слушайте и учитесь с нами.

ТелеграмПодкастБесплатные учебники