Синтаксис of S

Определение

Синтаксис of S – часть аргумента :nth-child() и :nth-last-child() из Selectors Level 4: браузер сначала отбирает детей по селектору S, а затем считает позиции только среди них. Во всех браузерах – с 2023 года.

4 мин 33 Обновлено 5 сентября

Отдельного селектора «:nth-child-of» в CSS не существует – of S это необязательная часть аргумента псевдоклассов :nth-child() и :nth-last-child(), описанная в Selectors Level 4. Запись :nth-child(2 of .highlight) означает «второй элемент среди детей, подходящих под селектор .highlight». Разработчики годами просили гипотетический «:nth-of-class» – возможность считать позиции не по тегу, как делает :nth-of-type(), а по произвольному селектору. Синтаксис of S закрыл именно этот запрос.

Как это работает

Грамматика по спецификации: :nth-child( [ An+B | even | odd ] of <complex-selector-list> ). Браузер действует в два шага: сначала отбирает среди детей родителя тех, кто матчит селектор S, затем применяет формулу An+B только внутри отфильтрованного набора. Остальные дети полностью игнорируются – для нумерации их как будто не существует. Элемент попадает под правило, только если он и матчит S, и стоит на нужной позиции внутри этого подмножества. Вместо формулы допустимы и ключевые слова: :nth-child(odd of .sale) возьмёт нечётные по счёту элементы среди детей с классом .sale.

S – полноценный список селекторов, а не только одиночный класс:

  • Несколько селекторов через запятую:nth-child(4 of .highlight, .sale) выберет четвёртый элемент среди детей с классом .highlight или .sale.
  • Псевдоклассы внутри S:nth-child(even of :not([hidden])) считает только видимые элементы; сам механизм отрицания разобран в статье о :not().

Важное ограничение: of S есть только у :nth-child() и :nth-last-child(). У :nth-of-type() такого аргумента нет – и он не нужен, потому что of S с селектором тега полностью перекрывает его возможности.

Пре-фильтр и пост-фильтр – в чём разница

Главный источник путаницы – отличие of S от привычной комбинации класса с псевдоклассом. Записи похожи, результат принципиально разный:

Пре-фильтр of S против пост-фильтра с классом
ЗаписьКак считает браузерИтог
.cls:nth-child(2)берёт второго ребёнка среди всех детей и проверяет, есть ли у него класспост-фильтр: если второй ребёнок без .cls – не выберется ничего
:nth-child(2 of .cls)сначала отбирает детей с .cls, затем берёт второго из нихпре-фильтр: второй элемент с классом, где бы он ни стоял
li.noted:nth-child(-n+3)ищет .noted среди первых трёх детей вообщеесли первые дети без класса – результат пустой
li:nth-child(-n+3 of .noted)нумерует только .noted и берёт первые трипервые три .noted при любых абсолютных позициях
/* второй элемент среди .highlight */
:nth-child(2 of .highlight) { outline: 2px solid coral; }

/* первые три .noted, где бы они ни стояли */
li:nth-child(-n + 3 of .noted) { border: 2px solid orange; }

/* сравните: .noted только среди первых трёх детей вообще */
li.noted:nth-child(-n + 3) { /* другой результат */ }

Зачем это нужно

Канонический кейс, который приводят и MDN, и Chrome for Developers, – зебра таблицы, не ломающаяся на скрытых строках. Обычный tr:nth-child(even) считает все строки, включая спрятанные фильтром: скройте одну – и чередование собьётся, рядом окажутся две строки одного цвета. Пре-фильтр решает проблему одной строкой кода: tr:nth-child(even of :not([hidden])) нумерует только видимые строки, и зебра остаётся ровной при любом состоянии фильтра.

Второй выигрыш – экономия на JavaScript. До кросс-браузерной поддержки такие задачи решали пересчётом классов скриптом либо полифиллом: известен паттерн на комбинации :has() и :not(), опубликованный Брамусом ван Даммом в декабре 2022 года. Теперь достаточно чистого CSS. Учитывайте только специфичность: по Selectors Level 4 к весу самого псевдокласса добавляется специфичность самого специфичного селектора из списка S.

Третий сценарий – разнотипные списки. В ленте, где вперемешку идут карточки статей, рекламные блоки и разделители, of S позволяет стилизовать «каждую вторую статью», не трогая остальных соседей: :nth-child(even of .post). Раньше для этого пришлось бы либо чистить разметку, либо навешивать классы скриптом при каждом изменении списка.

Поддержка синтаксиса of S в браузерах (caniuse, июль 2026)
БраузерМинимальная версия
Safari9+ (2015 год, реализовал первым)
Chrome и Edge111+ (март 2023)
Firefox113+ (май 2023)
Opera98+
Samsung Internet22+
IE и Opera Miniнет поддержки

С мая 2023 года, когда фичу получил Firefox, синтаксис имеет статус Baseline 2023 (Newly available). Глобальная поддержка по caniuse на июль 2026 – около 92%.

Пример

Типовая задача на Битрикс-проектах – таблица заказов или товаров с живой фильтрацией: JavaScript скрывает неподходящие строки атрибутом hidden, не перестраивая DOM. Обычная зебра в такой таблице разваливается после первого же клика по фильтру.

/* зебра только по видимым строкам */
.orders tr:nth-child(even of :not([hidden])) {
  background-color: lightgrey;
}

/* последние три строки с классом .important */
.orders tr:nth-last-child(-n + 3 of .important) {
  font-weight: bold;
}

Первое правило красит каждую вторую видимую строку: скрытые не участвуют в нумерации, и чередование остаётся ровным при любом наборе фильтров. Второе выделяет последние три строки с классом .important – отсчёт с конца делает :nth-last-child() с тем же пре-фильтром. Перед выкаткой загляните в отчёт Яндекс Метрики по браузерам вашей аудитории: при глобальной поддержке около 92% фолбэк чаще всего не нужен, но если заметна доля старых Android-браузеров или Opera Mini, оставьте обычную зебру запасным вариантом. Тот же приём работает в сетке товаров каталога: скрывайте отфильтрованные позиции атрибутом hidden – и чередование карточек останется ровным без единой строки JavaScript. Как устроены сами формулы An+B, odd/even и диапазоны – в базовой статье о псевдоклассе :nth-child().

Частые вопросы

Чем :nth-child(2 of .cls) отличается от .cls:nth-child(2)?

:nth-child(2 of .cls) – пре-фильтр: браузер сначала отбирает детей с классом .cls и берёт второго из них, где бы он ни стоял среди остальных. .cls:nth-child(2) – пост-фильтр: берётся второй ребёнок вообще, и правило сработает, только если у него есть класс .cls. Если второй ребёнок без класса, второй вариант не выберет ничего.

Можно ли передать в of несколько селекторов?

Да, S – это полноценный список селекторов через запятую: :nth-child(4 of .highlight, .sale) выберет четвёртый элемент среди детей, подходящих хотя бы под один из селекторов. Внутри S работают и псевдоклассы, например :not([hidden]).

Работает ли of S в :nth-of-type()?

Нет. Аргумент of S есть только у :nth-child() и :nth-last-child(). Он и не нужен: запись :nth-child(2 of li) с селектором тега полностью перекрывает возможности :nth-of-type() и расширяет их на любые селекторы.

Как сделать зебру таблицы, которая не ломается на скрытых строках?

Используйте пре-фильтр по видимости: tr:nth-child(even of :not([hidden])). Браузер нумерует только строки без атрибута hidden, поэтому при скрытии части строк фильтром чередование фона пересчитывается и остаётся ровным.

Какие браузеры поддерживают of S и нужен ли фолбэк?

Safari поддерживает с версии 9 (2015 год), Chrome и Edge – с 111 (март 2023), Firefox – с 113 (май 2023); статус Baseline 2023. Глобальная поддержка по caniuse на июль 2026 – около 92%. Не поддерживают IE и Opera Mini: если они заметны в вашей аудитории, оставьте обычное правило без of S запасным вариантом.

Как of S влияет на специфичность селектора?

По Selectors Level 4 :nth-child() – псевдокласс со специфичностью (0,1,0), и при наличии аргумента of S к ней добавляется специфичность самого специфичного селектора из списка S. То есть :nth-child(2 of #id) весит больше, чем :nth-child(2 of .cls).

Это и есть «nth-of-class», который давно просили разработчики?

По сути да. Отдельный псевдокласс :nth-of-class в спецификацию не вошёл, вместо него в Selectors Level 4 добавили аргумент of S. caniuse описывает его как обобщение :nth-of-type: то же самое, но фильтр не по тегу, а по произвольному селектору.

Связанные термины

Selectors Level 4 Selectors Level 4 – модуль спецификации CSS от W3C, расширивший селекторы: :is(), :where(), :has(), :not() со списком, :nth-child(An+B of S). Статус – Working Draft (редакция 22.01.2026), но ядро давно поддержано всеми браузерами. Псевдокласс :has() :has() – реляционный CSS-псевдокласс из Selectors Level 4: выбирает элемент по наличию потомка, соседа или состояния внутри. Долгожданный «родительский селектор» работает во всех браузерах с декабря 2023 (Firefox 121). Псевдокласс :not() :not() – CSS-псевдокласс отрицания: выбирает элементы, не соответствующие селектору-аргументу. В Selectors Level 4 принимает список селекторов (:not(.a, .b)) – кроссбраузерно с января 2021 (Chrome 88, Firefox 78, Safari 9). Псевдокласс :nth-child() :nth-child() – CSS-псевдокласс, выбирающий элементы по позиции среди всех детей родителя: по номеру, ключевым словам odd/even или формуле An+B. Нумерация начинается с 1, а не с 0. Псевдокласс :nth-last-child() :nth-last-child() – CSS-псевдокласс, выбирающий элементы по позиции среди соседей с отсчётом от конца родителя: nth-last-child(1) – последний элемент. Принимает те же аргументы, что :nth-child(): число, odd/even, формулу An+B. Псевдокласс :nth-of-type() :nth-of-type() – CSS-псевдокласс, считающий позицию элемента только среди соседей с тем же тегом: p:nth-of-type(2) – второй абзац, даже если между абзацами стоят div или заголовки. Синтаксис аргумента общий с :nth-child().

Материалы по теме

Что почитать дальше по этой теме

Статья Что боты находят на сайте, а вы – нет Боты ходят по изнанке сайта, куда живой человек не забредёт, и фиксируют в логах то, чего не видно ни в Метрике, ни на витрине: падающие с ошибкой 500 страницы каталога, битый файл с 747 обращениями, поток сканеров секретов. Разбираю на реальных логах, что искать и как чинить. 7 мин 217 22 июля 2026 Инструкция Как выгрузить и читать access-логи, если хостинг хранит их три дня Access-лог – единственное место, где виден весь трафик сайта, включая ИИ-ботов, которых не замечают счётчики. Разбираю на практике: где взять логи, как не потерять их из-за ротации, какие команды показывают ботов, ошибки и подозрительную активность. 7 мин 170 21 июля 2026 Флагманский гайд AI-анализ email-обращений: методика на стыке Яндекс.Метрики и Claude Code Классический email-трекинг отвечает на вопрос «откуда пришло обращение». AI-слой отвечает на вопросы, которые раньше требовали ручного аналитика: значим ли email на фоне звонков, форм и мессенджеров, почему один источник даёт качественные обращения, а другой – пустые, какие сегменты визитов предшествуют письму, что написать в ответ с учётом пути пользователя. Здесь – как я собираю это на уже имеющемся стеке: Logs API Метрики, PostgreSQL и Claude Code, без новых платных сервисов. 11 мин 297 26 мая 2026 Флагманский гайд Майкор: ИИ-аудит проекта по 4 точкам контакта Майкор – это перекрёстный ИИ-аудит проекта в 4 точках контакта: сайт, контекстная реклама, AI-поиск и Яндекс.Карты. Я анализирую каждую систему и смотрю связки между ними – где маркетинг рассказывает одно, реклама ведёт на другое, а AI-системы цитируют третий номер телефона. В одном из моих аудитов медицинской клиники в Москве у организации в индексе AI-сервисов оказалось 6 разных номеров и всего 7 упоминаний на 64 проверочных запроса – при том, что в обычной выдаче Яндекса клиника была в топ-1. Майкор закрывает такие разрывы за один аудит вместо четырёх раздельных. 16 мин 501 13 мая 2026 Гайд FAQPage Schema: как разметить блок частых вопросов и попасть в AI-ответы FAQPage schema – один из самых эффективных типов разметки для попадания в AI-ответы. Страницы с FAQPage schema цитируются AI-поисковиками в 2,7 раза чаще. В этом гайде – формат разметки, правила написания ответов для AI, реализация на 1С-Битрикс и типичные ошибки, которые обнуляют эффект. 8 мин 331 25 апреля 2026