Псевдокласс :nth-child()

:nth-child() – CSS-псевдокласс, выбирающий элементы по позиции среди всех детей родителя: по номеру, ключевым словам odd/even или формуле An+B. Нумерация начинается с 1, а не с 0.

4 минуты чтения

Псевдокласс :nth-child() появился ещё в третьей версии спецификации селекторов, а его актуальная грамматика описана в Selectors Level 4. Он выбирает элементы по порядковому номеру в списке детей родителя: третий пункт меню, каждая чётная строка таблицы, каждый третий товар в сетке. Принципиальный момент – позиция считается среди всех соседних элементов независимо от тега. Этим он отличается от :nth-of-type(), который нумерует только элементы одного типа, и этим же объясняется большинство ситуаций «селектор не работает» у новичков.

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

Браузер перебирает детей родителя и сверяет номер каждого с паттерном из аргумента. Нумерация начинается с 1, а не с 0: :nth-child(1) эквивалентен :first-child, а :nth-child(0) не выберет ничего. Аргумент принимает три формы:

  • Число – конкретная позиция: li:nth-child(3) выберет третий элемент списка.
  • Ключевые словаodd (нечётные позиции: 1, 3, 5…) и even (чётные: 2, 4, 6…), полные синонимы формул 2n+1 и 2n.
  • Формула An+B – A задаёт шаг, B – смещение, а n пробегает неотрицательные целые числа: 0, 1, 2 и далее. Если результат формулы нулевой или отрицательный, элемент на такой позиции просто не выбирается.

Проверить любую формулу можно простой подстановкой: для 3n+4 при n = 0, 1, 2 получаются позиции 4, 7 и 10 – каждый третий элемент начиная с четвёртого. Отрицательный коэффициент разворачивает выборку: -n+3 даёт позиции 3, 2 и 1, то есть первые три элемента.

/* зебра списка */
li:nth-child(even) { background-color: lightyellow; }

/* первые три пункта */
li:nth-child(-n + 3) { border: 2px solid orange; }

/* вторая колонка любой таблицы */
tbody tr :nth-child(2) { text-align: center; }

Формула An+B: таблица-шпаргалка

Типовые формулы An+B и что они выбирают
ЗаписьКакие позицииТиповая задача
2n (even)2, 4, 6…зебра списков и таблиц
2n+1 (odd)1, 3, 5…зебра с первой строки
3n3, 6, 9…каждый третий элемент сетки
3n+44, 7, 10…каждый третий начиная с четвёртого
n+7с 7-й до концавесь «хвост» длинного списка
-n+3первые триакцент на первых карточках
1только перваяэквивалент :first-child

Диапазон задаётся цепочкой из двух условий: :nth-child(n+8):nth-child(-n+15) выберет элементы с 8-го по 15-й включительно. Отсчёт с конца – задача зеркального псевдокласса :nth-last-child(): запись :nth-last-child(-n+3) означает «последние три».

Почему li:nth-child(2) может «не работать»

В селекторе span:nth-child(2n+1) позиция считается среди всех соседей любого типа, но правило применяется только к тем нечётным позициям, где действительно стоит span. Классический пример из документации MDN: у родителя пять детей – span, span, span, em, span. Выделятся span на позициях 1, 3 и 5, а em на позиции 4 визуально «ломает» ожидаемое чередование: подсвеченные третий и пятый span оказываются рядом. Если считать нужно только элементы конкретного тега – берите :nth-of-type(), а если фильтровать по произвольному селектору – синтаксис of S, где браузер сначала отбирает детей по селектору и лишь потом нумерует.

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

Главная ценность – стилизация по позиции без лишних классов в разметке и без JavaScript. Типовые задачи:

  • Зебра – чередование фона строк таблицы или пунктов списка, самый цитируемый кейс во всех справочниках.
  • Ритмичная сетка – каждый третий или четвёртый элемент каталога получает другой размер или отступ.
  • Акценты на краях – первые N карточек крупнее, у последних нет разделителя.
  • Вёрстка, зависящая от количества – комбинации :nth-child() и :nth-last-child() меняют стиль в зависимости от числа элементов в контейнере.

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

Для бизнеса это означает меньше правок шаблонов: контент-менеджер добавляет и удаляет элементы, а чередование и акценты перестраиваются сами. С поддержкой всё спокойно: базовый :nth-child() работает во всех браузерах с июля 2015 года (статус Baseline Widely Available по MDN), а исторически поддерживался ещё с IE9. По специфичности это обычный псевдокласс – (0,1,0), столько же, сколько у класса.

Пример

Каталог товаров: нужно выделить первые три карточки как хиты, задать зебру спискам характеристик и подсветить строки прайса с 4-й по 8-ю, где стоят акционные позиции.

/* первые три карточки – хиты */
.catalog .card:nth-child(-n + 3) { box-shadow: 0 0 0 2px coral; }

/* зебра характеристик */
.specs li:nth-child(even) { background-color: lightyellow; }

/* акционные строки прайса: с 4-й по 8-ю */
.price tr:nth-child(n + 4):nth-child(-n + 8) { background-color: honeydew; }

На Битрикс-проектах я использую этот приём постоянно: компоненты вида news.list выводят элементы однородным списком, и позиционные псевдоклассы позволяют оформить «каждый третий баннер шире» или «первые два поста крупнее» без правки PHP-логики и без условных классов в шаблоне. Единственная ловушка – убедиться, что в контейнере нет посторонних детей вроде технических обёрток или скрытых блоков: они тоже занимают позиции и сдвигают нумерацию. В шаблонах Битрикса такое случается регулярно: отложенный баннер, пустой div под скрипт или невидимый элемент пагинации становятся «лишними» детьми контейнера и смещают зебру на одну позицию. Если скрытые элементы неизбежны, зебру спасает пре-фильтр of :not([hidden]) – подробный разбор в статье о синтаксисе of S.

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

Почему :nth-child(0) ничего не выбирает?

Нумерация детей в :nth-child() начинается с 1, а не с 0. Позиций с нулевым или отрицательным номером не существует, поэтому :nth-child(0) не совпадёт ни с одним элементом. Первый ребёнок – это :nth-child(1), он же :first-child.

Чем odd и even отличаются от 2n+1 и 2n?

Ничем – это полные синонимы. odd эквивалентно формуле 2n+1 и выбирает позиции 1, 3, 5 и далее, even эквивалентно 2n и выбирает позиции 2, 4, 6. Ключевые слова просто читаются легче, чем формулы.

Как выбрать первые или последние N элементов?

Первые три – :nth-child(-n+3): при n = 0, 1, 2 формула даёт позиции 3, 2 и 1, а дальше уходит в минус. Последние три – зеркальная запись :nth-last-child(-n+3), которая считает позиции с конца списка.

Почему li:nth-child(2) не сработал, хотя это второй li в списке?

:nth-child() считает всех детей родителя, включая элементы других тегов. Если перед вашим li стоит, например, заголовок или div, второй li на самом деле занимает третью позицию. Считать только элементы конкретного типа умеет :nth-of-type(), а фильтровать по произвольному селектору – синтаксис of S.

Как выбрать диапазон элементов, например с 4-го по 8-й?

Цепочкой из двух условий: :nth-child(n+4):nth-child(-n+8). Первое условие отбирает все элементы начиная с четвёртого, второе – первые восемь; пересечение даёт диапазон с 4-го по 8-й включительно.

Считает ли :nth-child() текстовые узлы и комментарии?

Нет. В нумерации участвуют только элементы – теги внутри родителя. Текстовые узлы, пробелы и HTML-комментарии позиций не занимают и на подсчёт не влияют.

Влияет ли :nth-child() на специфичность селектора?

Да, это псевдокласс, поэтому он добавляет специфичность (0,1,0) – столько же, сколько обычный класс. По спецификации Selectors Level 4 у варианта с аргументом of S к этому добавляется специфичность самого специфичного селектора из списка S.

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

Валентина Меланина

Нужна консультация?

Разберу ваш сайт и покажу точки роста

Если хотите понять, как этот термин применить к вашему проекту — начнём с аудита.