CSS-селектор — это шаблон, который указывает к каким HTML-элементам применить стиль. Тег, класс, ID, атрибут, потомок, псевдокласс — разбираем все типы с примерами.

- Основные типы селекторов
- Комбинированные селекторы
- Атрибутные селекторы
- Специфичность (Specificity) — как CSS выбирает победителя
- Современные селекторы — :is(), :where(), :not()
- Часто задаваемые вопросы о CSS селекторах
- Что такое специфичность в CSS?
- Как выбрать каждый чётный/нечётный элемент?
- :is() и :where() — в чём разница?
Основные типы селекторов
/* Тег — все элементы этого типа */
p { color: #374151; line-height: 1.6; }
h1 { font-size: 2.5rem; font-weight: 700; }
button { cursor: pointer; }
/* Класс — элементы с данным классом */
.card { border-radius: 12px; background: white; }
.active { background: #2563eb; color: white; }
.hidden { display: none; }
/* ID — уникальный элемент на странице */
#header { position: sticky; top: 0; z-index: 100; }
#sidebar { width: 280px; }
/* Универсальный — все элементы */
* { box-sizing: border-box; margin: 0; padding: 0; }
/* Несколько классов — оба должны быть у элемента */
.btn.primary { background: #2563eb; }
.btn.danger { background: #dc2626; }
/* <button class="btn primary"> — применится первое */
/* <button class="btn"> — не применится */

Комбинированные селекторы
/* Потомок (пробел) — любой уровень вложенности */
.card p { font-size: 0.9rem; }
/* ← все <p> внутри .card (дети, внуки, правнуки) */
nav a { text-decoration: none; color: inherit; }
/* ← все <a> внутри nav */
/* Дочерний (>) — только прямые дети */
ul > li { margin-bottom: 8px; }
/* ← только <li> прямо в <ul>, не вложенные */
.nav > .nav-item > a { padding: 8px 16px; }
/* Соседний (+) — следующий сразу за */
h2 + p { margin-top: 0; font-size: 1.1rem; }
/* ← только <p> идущий СРАЗУ после <h2> */
label + input { display: block; margin-top: 4px; }
/* Общий соседний (~) — все последующие на том же уровне */
h2 ~ p { color: #6b7280; }
/* ← все <p> после <h2> на том же уровне (не только первый) */
/* Группировка (,) — применить к нескольким */
h1, h2, h3, h4, h5, h6 {
font-weight: 700;
line-height: 1.3;
color: #111827;
}

Атрибутные селекторы
/* [attr] — есть атрибут (любое значение) */
input[required] { border-color: #dc2626; }
a[target] { font-weight: 500; }
[disabled] { opacity: 0.5; cursor: not-allowed; }
/* [attr="value"] — точное совпадение */
input[type="email"] { /* поле email */ }
input[type="password"] { font-family: monospace; }
input[type="checkbox"] { width: auto; }
a[rel="noopener"] { /* внешние ссылки */ }
/* [attr^="value"] — начинается с (^ = каретка) */
a[href^="https"] { color: #16a34a; } /* безопасные HTTPS */
a[href^="mailto"]{ color: #2563eb; } /* email ссылки */
a[href^="tel"] { color: #7c3aed; } /* телефонные */
[class^="icon-"] { display: inline-block; }
/* [attr$="value"] — заканчивается на ($ = доллар) */
a[href$=".pdf"] { padding-right: 20px; } /* ссылки на PDF */
a[href$=".doc"] { /* Word документы */ }
img[src$=".svg"] { /* SVG изображения */ }
/* [attr*="value"] — содержит (* = звёздочка) */
[class*="col-"] { /* любые колонки */ }
a[href*="github"] { /* ссылки на GitHub */ }
[class*="btn-"] { display: inline-flex; align-items: center; }
/* [attr~="value"] — содержит слово (в списке через пробел) */
[class~="card"] { /* элементы с классом "card" (среди других классов) */ }
/* [attr|="value"] — равно или начинается с "value-" (для lang) */
[lang|="en"] { /* lang="en" или lang="en-US" */ }

Специфичность (Specificity) — как CSS выбирает победителя
Когда несколько правил применяются к одному элементу, побеждает правило с наибольшей специфичностью. Считается как четырёхзначное число.
| Тип селектора | Специфичность | Пример |
|---|---|---|
Инлайн style="" | 1-0-0-0 | <p style="color:red"> |
| ID (#id) | 0-1-0-0 | #header |
| Класс (.class) | 0-0-1-0 | .card |
| Атрибут [attr] | 0-0-1-0 | [type="text"] |
| Псевдокласс (:hover) | 0-0-1-0 | :first-child |
| Тег (div, p) | 0-0-0-1 | p, div |
| Псевдоэлемент (::before) | 0-0-0-1 | ::after |
| Универсальный (*) | 0-0-0-0 | * |

/* Примеры вычисления специфичности */
p { color: blue; }
/* 0-0-0-1 */
.card p { color: gray; }
/* 0-0-1-1 = класс + тег */
#main .card p { color: green; }
/* 0-1-1-1 = ID + класс + тег */
/* Побеждает: #main .card p (наибольшая специфичность) */
/* ID всегда сильнее любого числа классов */
#header { color: red; } /* 0-1-0-0 */
.a.b.c.d.e { color: blue; } /* 0-0-5-0 — проигрывает ID! */
/* !important перебивает всё */
p { color: red !important; } /* всегда победит */
/* Используй только в крайнем случае */

Современные селекторы — :is(), :where(), :not()
/* :is() — группировка, сохраняет специфичность самого специфичного */
:is(h1, h2, h3, h4) { line-height: 1.3; }
/* = h1, h2, h3, h4 { } но короче */
/* Вложенные контексты */
:is(article, section, aside) :is(h1, h2, h3) {
color: #1d4ed8;
}
/* = article h1, article h2, ... — 9 комбинаций в 1 правиле */
/* :where() — как :is(), но специфичность = 0 */
/* Удобно для сброса стилей, которые легко переопределить */
:where(h1, h2, h3) { margin-top: 0; }
/* Любой более специфичный селектор перебьёт */
/* :not() — отрицание */
p:not(.lead) { color: #6b7280; } /* все p кроме .lead */
li:not(:last-child) { margin-bottom: 8px; } /* все li кроме последнего */
a:not([href]) { color: gray; cursor: default; } /* ссылки без href */
/* :not() с несколькими условиями (CSS4) */
.item:not(.disabled, .hidden) { cursor: pointer; }
/* :has() — родительский селектор (CSS4) */
.card:has(img) { padding: 0; }
/* .card, у которой есть img */
label:has(+ input:required) { font-weight: 600; }
/* label рядом с required input */

Часто задаваемые вопросы о CSS селекторах
Что такое специфичность в CSS?
Специфичность — «вес» селектора, определяющий чьё правило победит при конфликте. Считается как четырёхзначное число (a-b-c-d): a — инлайн стили, b — ID, c — классы/атрибуты/псевдоклассы, d — теги. Сравниваются слева направо: более высокое значение в любой позиции побеждает. ID всегда сильнее любого количества классов. Избегай ID в CSS и не злоупотребляй !important — это делает код непредсказуемым.
Как выбрать каждый чётный/нечётный элемент?
Используй псевдоклассы :nth-child(). :nth-child(even) — чётные, :nth-child(odd) — нечётные. Или формула :nth-child(2n) — каждый второй, :nth-child(3n+1) — каждый третий начиная с первого.
tr:nth-child(even) { background: #f9fafb; } /* зебра в таблице */
tr:nth-child(odd) { background: white; }
.cards:nth-child(3n+1) { background: blue; } /* 1, 4, 7, 10... */
li:first-child { font-weight: bold; } /* первый */
li:last-child { margin-bottom: 0; } /* последний */
li:nth-child(2) { color: red; } /* второй точно */

:is() и :where() — в чём разница?
Оба упрощают групповые селекторы. Разница в специфичности: :is() берёт специфичность самого сильного аргумента — :is(#id, .class) будет иметь специфичность ID. :where() всегда имеет специфичность 0, что делает его идеальным для базовых reset-стилей, которые легко переопределить любым классом или тегом.




