Селекторы и псевдоклассы
Селекторы по атрибутам, комбинаторы, nth-child, :is/:where/:has, :not и псевдоклассы состояний для точной стилизации.
1. Виды селекторов
- тег: p, a, button — по имени элемента;
- класс: .card — самый частый и конкретный;
- id: #hero — один на странице;
- атрибут: [type="text"], [data-count];
- комбинаторы: div > p, h2 + p, section p.
.card p { color: #333; } /* потомок: любой p внутри класса */
.nav > li { display: inline; } /* сын: прямой ребёнок */
h2 + p { margin-top: 0; } /* сосед сразу после h2 */
ul ~ .foot { color: gray; } /* следующий брат-секция */2. Селекторы по атрибутам
Атрибуты дают точечный отбор по значению и его наличию — отлично для форм, ссылок и data-атрибутов.
[href^="https://"] { color: green; } /* начинается с */
[href$=".pdf"] { color: red; } /* заканчивается на */
[href*="download"] { font-weight: bold; } /* содержит */
[type="email"][required] { border-color: #f59e0b; }- [attr] — есть атрибут;
- [attr="v"] — точное значение;
- операторы ^=, $=, *=, |=, ~= — начало, конец, содержит, список-турб.
3. nth-child и nth-of-type
nth-child считает всех детей, nth-of-type — только элементы типа. Классика: окраска полос в таблице, номера карточек, отступы в списках.
.table tr:nth-child(even) { background: #f8fafc; }
.chat li:nth-child(2) { font-weight: bold; }
.grid > *:nth-child(3n + 1) { margin-left: 0; }
/* формулы: 2n+1 — нечётные, 3n — каждый третий, советы первые два */4. Псевдоклассы состояния (:hover и другое)
- :hover, :active — наведение и нажатие;
- :focus, :focus-visible — фокус (focus-visible для клавиатуры);
- :disabled, :checked, :invalid, :required — состояние формы;
- :visited — посещённая ссылка;
- :target — элемент, на который прыгнули якорем.
.btn:hover { background: #1d4ed8; }
.btn:focus-visible { outline: 3px solid #93c5fd; }
input:checked + label { color: #2563eb; }
input:required { border-color: #f59e0b; }5. :not, :nth, комбинации
:not() отрицает селектор внутри. Внутри можно комбинировать селекторы и перечислять через запятую. :is() и :has() — мощный артиллерийский способ группировки.
input:not([type="hidden"]) { display: block; }
.card:not(.card--featured) { opacity: 0.85; }
/* :is() — «или» внутри селектора */
:is(h1, h2, h3) { margin-top: 1.2em; }
.card :is(.title, .desc) { color: #374151; }
/* :has() — родитель по присутствию ребёнка */
.card:has(img) { padding: 0; }
form:has(input:invalid) label { color: #dc2626; }
.menu:has(.menu__item.active) { border-color: #2563eb; }6. :where — обнуление веса
:where() ведёт себя как :is(), но его специфичность — ноль: стили внутри всегда могут быть перекрыты обычными правилами. Отлично для «дефолтов», которые должны уступать компонентам.
.card :where(h1, h2) { margin: 0; } /* вес = 0, любой .title перекроет */
:where(article, section) p { line-height: 1.6; }
/* разница: .card h2 имеет вес, :where(.card) h2 — нет */7. Специфичность на пальцах
Вес селектора считают: (id, классы/атрибуты/псевдоклассы, теги/псевдоэлементы). Чем больше левых единиц — тем сильнее. Два правила одной силы — побеждает то, что позже в файле.
#banner h2 { color: red; } /* (1,0,1) */
.page .title { color: blue; } /* (0,2,0) */
h2 { color: green; } /* (0,0,1) */
/* spec: {1,0,1} > {0,2,0} > {0,0,1} — победит #banner h2 */8. Псевдоклассы форм и ссылок
- :placeholder-shown — пока плейсхолдер виден;
- :user-invalid — после касания (не только при загрузке);
- :autofill — автозаполненное поле;
- :modal — открытый dialog;
- :blank и :invalid-формы — состояния полей.
.field:user-invalid { border-color: #dc2626; }
.field:placeholder-shown { background: #f9fafb; }
input:autofill { box-shadow: 0 0 0 50px #fff inset; }9. Практика: состояния меню и карточек
Сочетание всего: меню с активным пунктом и ховером, карточка, реагирующая на фокус и наличие изображения, форма, подсвечивающая ошибки.
.menu__link:hover { color: #2563eb; }
.menu__link:focus-visible { outline: 2px solid #2563eb; outline-offset: 4px; }
.menu__link.is-active, .menu__link[aria-current="page"] { font-weight: 600; }
.card { cursor: pointer; }
.card:has(.card__badge) .card__title { margin-bottom: 12px; }
.card:hover { transform: translateY(-2px); }10. Производительность селекторов
- индексы селекторов неважны для современных движков (только не в тесных циклах);
- страшнее — тяжёлые :has() и deep-селекторы в больших стилях;
- один класс — один элемент: не пишите .card.card.card или div.card p;
- глубокие цепочки (header .nav ul li a) хрупче: меняется разметка — ломается стиль.
11. Чек-лист селекторов
- основной вес на классах — плоскость специфичности;
- :is()/:not()/:where() облегчают правила;
- :has() — родитель по ребёнку (с осторожностью);
- состояния оформляются псевдоклассами, а не классом-копией;
- focus-visible — обязательно для клавиатуры;
- длинные цепочки селекторов — признак слабой архитектуры.
Что дальше
Курс завершён.