Селекторы CSS: виды, комбинаторы, псевдоклассы и специфичность

опубликовано
обновлено
читать
≈ 7 мин
автор
среда и версия
CSS; пример и три правки проверены в HTML/CSS-песочнице Koddo (Chromium) 20 октября 2026.

Пишешь .task { color: red; }, а пункт списка остаётся чёрным. Часто причина в том, что к нему подходит другое правило, и оно сильнее. Чтобы предсказывать, какое правило сработает, нужно понимать две вещи: как селектор находит элементы и как браузер выбирает между правилами.

Селектор — первая часть CSS-правила: он говорит, к каким элементам применить свойства. В правиле .tasks li { padding: 8px; } селектор .tasks li выбирает пункты списка внутри элемента с классом tasks. Селекторы бывают простыми — по тегу, классу, id и атрибуту, их можно соединять комбинаторами, а когда к элементу подходят два правила, побеждает более специфичное.

Пример: один список, девять селекторов

Открой пример в песочнице HTML/CSS ссылкой под вторым блоком: разметка попадёт во вкладку index.html, стили — в styles.css. Каждое правило в CSS выбирает элементы по-своему, ниже разберём все.

HTML — список дел с классами, id и ссылками:

<main class="board">
  <h1 id="title">Планы на неделю</h1>
  <ul class="tasks">
    <li class="task done">Купить зерно</li>
    <li class="task">Позвонить поставщику</li>
    <li class="task urgent">Оплатить аренду</li>
    <li class="task">Обновить меню</li>
  </ul>
  <p>Подробности — на <a href="https://example.com">сайте поставщика</a> и в <a href="/menu">меню</a>.</p>
</main>

CSS — каждое правило со своим селектором:

body {
  margin: 0;
  padding: 1rem;
  font-family: system-ui, sans-serif;
}

h1 {
  font-size: 1.5rem;
}

.tasks {
  padding: 0;
  list-style: none;
}

.tasks li {
  padding: 0.5rem 0.75rem;
  border-bottom: 1px solid #dddddd;
}

.tasks li:nth-child(even) {
  background: #f4f6fa;
}

.task.urgent {
  color: #c62828;
  font-weight: 700;
}

.task.done::before {
  content: "✓ ";
  color: #2e7d32;
}

.task:not(.done):hover {
  background: #fff3e0;
}

a[href^="https"] {
  color: #6a1b9a;
}

Что получится: второй и четвёртый пункты на светлом фоне, «Оплатить аренду» красным жирным, перед «Купить зерно» зелёная галочка, а ссылка на внешний сайт — фиолетовая, тогда как ссылка на /menu осталась обычной синей. Наведи курсор на любой несделанный пункт: он подсветится.

Простые селекторы: тег, класс, id и атрибут

По тегу. h1, p, li выбирают все элементы с таким именем. Удобно для общих правил: шрифт body, отступы заголовков.

По классу. .tasks — точка и имя класса. Один класс можно дать сколько угодно элементам, а у элемента может быть несколько классов через пробел: class="task urgent". Классы — основной способ оформлять страницу.

По id. #title — решётка и id. Id на странице должен быть один, поэтому такой селектор выбирает один элемент. Для стилей id берут редко: он слишком сильный в споре правил, об этом ниже.

По атрибуту. В квадратных скобках: [type="email"] — поля с таким типом, [href^="https"] — ссылки, адрес которых начинается с https. Есть и другие варианты сравнения: $= — заканчивается на, *= — содержит.

Простые селекторы можно склеивать без пробела, тогда элемент должен подходить под все сразу. .task.urgent — элемент с обоими классами, li.task — пункт списка с классом task. А через запятую пишут группу: h1, h2 { … } даёт одни стили обоим.

Комбинаторы: потомок, ребёнок и соседи

Комбинатор описывает, как два элемента связаны в дереве страницы:

.tasks li { }    /* li где угодно внутри .tasks */
.tasks > li { }  /* li — прямой ребёнок .tasks */
h2 + p { }       /* p сразу после h2 */
h2 ~ p { }       /* все p после h2 у того же родителя */

Пробел — потомок. .tasks li найдёт пункт на любой глубине, даже во вложенном списке.

Знак > — ребёнок. .tasks > li возьмёт только пункты верхнего уровня, вложенные списки останутся без этих стилей.

Знаки + и ~ — соседи. Оба смотрят на элементы с тем же родителем: + выбирает следующего сразу за первым, ~ — всех следующих.

Пробел в селекторе — это тоже комбинатор, поэтому .task.urgent и .task .urgent выбирают разное. Первый — элемент с двумя классами, второй — элемент с классом urgent внутри элемента с классом task.

Псевдоклассы и псевдоэлементы

Псевдоклассы. Двоеточие и слово выбирают элемент по состоянию или месту. :hover — под курсором, :focus-visible — в фокусе с клавиатуры, :checked — отмеченный флажок, :first-child и :last-child — первый и последний среди соседей. :nth-child(even) берёт чётные, :nth-child(odd) — нечётные, а :nth-child(3n + 1) — первый, четвёртый, седьмой и так далее. :not(.done) выбирает всё, кроме подходящего под скобки.

Псевдоэлементы. Два двоеточия выбирают часть элемента, которой нет в HTML. ::before и ::after добавляют содержимое до и после текста — им обязательно нужно свойство content, иначе они не появятся. ::placeholder оформляет подсказку в поле ввода, ::selection — выделенный текст. Старая запись с одним двоеточием, :before, тоже работает.

Если хочется потренировать :nth-child, в игре «Повтори макет» есть уровень «Шахматы»: доску 4 × 4 там красят как раз через :nth-child.

Какое правило победит: специфичность и порядок

Наведи курсор на второй пункт примера. К нему подходят два правила с фоном: .tasks li:nth-child(even) и .task:not(.done):hover. Побеждает второе: браузер сравнивает специфичность — три числа, которые он считает для каждого селектора.

CSS / 01

Специфичность — счёт из трёх чисел

Специфичность пяти селекторов из примераШаг 1: у каждого селектора три числа — A, сколько в нём id; B — классов, атрибутов и псевдоклассов; C — тегов и псевдоэлементов. h1 — 0, 0, 1; .tasks li — 0, 1, 1; .task.urgent — 0, 2, 0; .tasks li:nth-child(even) — 0, 2, 1; #title — 1, 0, 0. Шаг 2: числа сравнивают слева направо, решает первое отличие: .task.urgent сильнее .tasks li. Шаг 3: при равном счёте побеждает правило, которое стоит ниже.01 / считаем: A — id, B — классы, C — тегиA · idB · классыC · тегиh1001.tasks li011.task.urgent020.tasks li:nth-child(even)021#title10002 / сравниваем слева направо: решает первое отличие.task.urgent (0 · 2 · 0) сильнее .tasks li (0 · 1 · 1) — красный цвет останется03 / счёт равный — побеждает правило, которое ниже
Числа сравнивают слева направо: один #id сильнее любого числа классов, а один класс сильнее любого числа тегов. Атрибуты и псевдоклассы считаются как классы, псевдоэлементы — как теги.

У .task:not(.done):hover счёт 0 · 3 · 0: класс .task, псевдокласс :hover и :not(), который считается по своему аргументу .done. Это больше, чем 0 · 2 · 1 у правила с чётными пунктами, поэтому подсветка видна и на светлом фоне.

Равный счёт — решает порядок. Из двух одинаково сильных правил применится то, что ниже в CSS.

Стиль в атрибуте сильнее селекторов. style="color: red" в HTML перебивает любое правило из styles.css.

!important — крайняя мера. color: red !important перебивает всё остальное, но потом его можно перебить только другим !important. Обычно хватает селектора посильнее.

Наследование слабее любого правила. Цвет, который пункт получил от родителя, уступает любому правилу, выбравшему сам пункт, даже *.

Шпаргалка селекторов CSS

СелекторЧто выбираетСпецифичность
*все элементы0 · 0 · 0
pвсе абзацы0 · 0 · 1
.cardэлементы с классом card0 · 1 · 0
#titleэлемент с id="title"1 · 0 · 0
[type="email"]элементы с таким атрибутом0 · 1 · 0
[href^="https"]атрибут начинается с https0 · 1 · 0
[href$=".pdf"]атрибут заканчивается на .pdf0 · 1 · 0
.task.urgentэлемент с обоими классами0 · 2 · 0
h1, h2группа: и h1, и h2у каждого своя
.tasks lili где угодно внутри .tasks0 · 1 · 1
.tasks > lili — прямой ребёнок .tasks0 · 1 · 1
h2 + pp сразу после h20 · 0 · 2
h2 ~ pвсе p после h2 у того же родителя0 · 0 · 2
a:hoverссылка под курсором0 · 1 · 1
li:nth-child(odd)нечётные пункты0 · 1 · 1
li:not(.done)пункты без класса done0 · 1 · 1
p::first-lineпервая строка абзаца0 · 0 · 2
.task::beforeсодержимое перед текстом0 · 1 · 1

Три правки, чтобы закрепить

Открой пример в песочнице и перед каждой правкой предскажи результат:

  1. Замени :nth-child(even) на :nth-child(odd). Светлый фон перейдёт на первый и третий пункты.
  2. Поставь пробел между классами: .task .urgent. «Оплатить аренду» перестанет быть красной: теперь селектор ищет элемент с классом urgent внутри .task, а внутри пунктов только текст.
  3. Дай первой ссылке id="supplier" и добавь правило #supplier { color: green; }. Ссылка станет зелёной, хотя правило a[href^="https"] тоже к ней подходит: 1 · 0 · 0 больше, чем 0 · 1 · 1.

Селекторы выбирают элементы, а дальше нужно их расставить: Flexbox выстраивает элементы в строку, CSS Grid — в сетку. Если разметка пока непривычна, начни со статьи про теги HTML.

Источники