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

:nth-of-type() – CSS-псевдокласс, считающий позицию элемента только среди соседей с тем же тегом: p:nth-of-type(2) – второй абзац, даже если между абзацами стоят div или заголовки. Синтаксис аргумента общий с :nth-child().

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

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

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

Для каждого ребёнка браузер берёт имя его тега, собирает одноимённых соседей и нумерует их сверху вниз начиная с 1. Аргументы стандартные для nth-семейства: число, odd/even или формула An+B. Синтаксиса of S у :nth-of-type() нет – он определён только для :nth-child() и :nth-last-child(). Классический пример из документации MDN – контейнер со смешанными тегами:

<div>
  <div>Этот элемент не считается.</div>
  <p>1-й абзац.</p>
  <p class="fancy">2-й абзац.</p>
  <div>Этот элемент не считается.</div>
  <p class="fancy">3-й абзац.</p>
  <p>4-й абзац.</p>
</div>
p:nth-of-type(2n + 1) { color: red; }        /* нечётные абзацы: 1-й и 3-й */
p:nth-of-type(2n)     { color: blue; }       /* чётные абзацы: 2-й и 4-й */
p:nth-of-type(1)      { font-weight: bold; } /* первый абзац */

Оба div при подсчёте абзацев игнорируются. Сравните с :nth-child(): здесь p:nth-child(2) выберет первый абзац, потому что он второй ребёнок родителя. Классический «обман» выглядит так: span:nth-child(3) исправно красит третий span, пока вёрстка однородна, но стоит вставить в контейнер div или ссылку – и третьим ребёнком становится другой элемент, селектор молча промахивается. Такие баги всплывают после безобидной правки контента и потому особенно неприятны: стили «ломаются сами», хотя CSS никто не трогал. p:nth-of-type(3) в той же ситуации продолжит указывать на третий абзац.

p.fancy:nth-of-type(2): класс проверяется после подсчёта

Частая ошибка – ожидание, что p.fancy:nth-of-type(2) выберет «второй абзац с классом fancy». На деле подсчёт идёт только по имени тега, а составной селектор работает как пост-фильтр: сначала браузер находит второй p среди всех p, потом проверяет, есть ли у него класс fancy. В разметке выше p.fancy:nth-of-type(2n+1) выберет только 3-й абзац: он нечётный по счёту абзацев и при этом с классом. «Второй элемент с классом» через :nth-of-type() выразить нельзя – MDN прямо пишет, что «nth-of-class» этим селектором не делается. Эту задачу закрывает современный синтаксис of S: p:nth-child(2 of .fancy).

nth-child, nth-of-type и of S – что выбрать

Выбор селектора по типу задачи
СелекторКого нумеруетТиповая задачаПоддержка
:nth-child(2)Всех детей родителя подрядПозиция в общем потоке: зебра таблицы, первые три карточкиВсе браузеры с 2015, IE9+
:nth-of-type(2)Только соседей с тем же тегомСчёт по тегу в смешанной разметке: второй абзац статьиВсе браузеры с 2015, IE9+
:nth-child(2 of .fancy)Только элементы, подходящие под селектор S«nth-of-class»: второй элемент с нужным классомChrome/Edge 111 (2023), Firefox 113 (2023), Safari 9

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

Польза раскрывается в смешанном контенте, где классы расставить нельзя или неудобно:

  • Типографика статей – каждый второй абзац, чередование фонов, буквица в первом абзаце: счёт не сбивается на заголовках и врезках.
  • Списки определений – dd:nth-of-type(even) подсветит чётные описания, игнорируя dt при подсчёте.
  • Вёрстка под CMS – когда HTML генерирует визуальный редактор или компонент и добавить классы к элементам невозможно.

Побочный бонус – чистота разметки: чем меньше служебных классов вроде first или odd, тем проще HTML, который читают и краулеры, и скринридеры. Логика чередования живёт в CSS, а контент-менеджер в админке не обязан помнить про специальные классы при каждой правке текста.

У псевдокласса целое семейство «по типу»: :first-of-type, :last-of-type, :only-of-type и :nth-last-of-type() – счёт по тегу с конца, по аналогии с :nth-last-child(). Когда разметка однородна – например, список из одних li, – :nth-child() и :nth-of-type() дают одинаковый результат, и лучше выбрать более привычный :nth-child(). А когда считать нужно по классу или атрибуту, а не по тегу, честнее сразу взять of S, чем подгонять пост-фильтры.

Пример

Типовая задача контент-хаба: текст статьи приходит из админки Битрикса единым HTML – заголовки, абзацы, таблицы и цитаты вперемешку, классов у абзацев нет. Нужно выделить первый абзац как лид и задать отступы остальным:

.article__body p:first-of-type {
  font-size: 1.25em;
}
.article__body p:nth-of-type(n + 2) {
  margin-top: 1em;
}

Здесь :first-of-type – то же, что :nth-of-type(1): он найдёт первый абзац, даже если перед ним стоят h2 или figure, тогда как p:nth-child(1) в такой разметке не выбрал бы ничего. Специфичность :nth-of-type() равна одному классу, поэтому правило легко переопределяется точечными стилями – подробнее в статье о специфичности CSS. Поддержка: по данным MDN, статус Baseline Widely Available, все браузеры с июля 2015 года, исторически IE9+ (Selectors Level 3) – префиксы и полифилы в 2026 году не нужны.

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

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

:nth-child() считает всех детей родителя подряд, независимо от тега, а :nth-of-type() – только соседей с тем же тегом. В контейнере из div и p селектор p:nth-child(2) выберет абзац, лишь если тот стоит вторым среди всех детей, а p:nth-of-type(2) – второй абзац при любом окружении.

Можно ли выбрать «второй элемент с классом» через :nth-of-type()?

Нет: :nth-of-type() считает только имена тегов, класс в подсчёте не участвует. «Nth-of-class» делается синтаксисом of S: :nth-child(2 of .fancy) выберет второй элемент с классом fancy. Поддержка of S: Chrome и Edge с версии 111, Firefox со 113, Safari с 9.

Что выберет p.fancy:nth-of-type(2)?

Второй p среди всех p родителя – и только при условии, что у этого абзаца есть класс fancy. Если второй абзац без класса, селектор не выберет ничего. Класс работает как пост-фильтр после подсчёта, а не как условие отбора «второй из .fancy».

Когда использовать :nth-of-type() вместо :nth-child()?

Когда в контейнере смешаны разные теги и нужен счёт по одному из них: абзацы среди заголовков, dd среди dt, td нужного уровня. В однородных списках оба псевдокласса дают одинаковый результат, и обычно пишут более привычный :nth-child().

Есть ли у :nth-of-type() синтаксис of S?

Нет. Аргумент of S определён в Selectors Level 4 только для :nth-child() и :nth-last-child(). В спецификации :nth-of-type() его нет, и браузеры такую запись не поддерживают.

Работают ли odd, even и формула An+B в :nth-of-type()?

Да, микросинтаксис аргумента общий для всей nth-группы: p:nth-of-type(odd) – нечётные абзацы, p:nth-of-type(2n) – чётные, p:nth-of-type(3n+1) – каждый третий начиная с первого. Считаются при этом только элементы того же тега.

«Type» в названии – это тег или класс?

Имя тега (тип элемента). Классы, id и атрибуты при построении списка для подсчёта не учитываются – они могут лишь отфильтровать уже найденные элементы. Поэтому счёт по классу этим селектором невозможен – для него существует of S.

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

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

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

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

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