Селекторы: как выбрать нужный элемент
По тегу, классу и id, комбинации, потомки и соседи, атрибуты, псевдоклассы и псевдоэлементы.
Что ты научишься делать
- Попадёшь стилем ровно в тот элемент, который нужен
- Разберёшься, чем потомок отличается от прямого ребёнка
- Добавишь состояния при наведении и фокусе без единой строчки JavaScript
#Три базовых селектора
/* по тегу — все абзацы страницы */p { color: #333; }/* по классу — все элементы с class="card" */.card { background: #f4f4f8; }/* по id — единственный элемент с id="hero" */#hero { min-height: 300px; }/* вообще все элементы */* { box-sizing: border-box; }Девяносто процентов настоящего CSS — это селекторы по классу. Тег берут для базовых вещей (сброс отступов, типографика), id в стилях лучше не использовать вовсе: почему — в следующем уроке.
#Комбинации
| Запись | Кого выбирает |
|---|---|
h1, h2, h3 | Группа: все три сразу. Запятая значит «или» |
.card p | Потомок: любой абзац внутри карточки, на любой глубине |
.card > p | Прямой ребёнок: только абзацы, лежащие непосредственно в карточке |
h2 + p | Следующий сосед: абзац сразу после заголовка |
h2 ~ p | Все следующие соседи: все абзацы после заголовка в том же родителе |
a.btn | Одновременно: ссылка, у которой есть класс btn. Без пробела! |
#Выбор по атрибуту
/* у элемента есть атрибут */[required] { border-color: #c8394a; }/* точное значение */input[type="email"] { background: #f0f6ff; }/* значение начинается с… */a[href^="https://"] { color: #0f8f6a; }/* заканчивается на… */a[href$=".pdf"]::after { content: " (PDF)"; }/* содержит подстроку */a[href*="youtube"] { color: #c8394a; }#Псевдоклассы: состояние и положение
Псевдокласс пишется через одно двоеточие и выбирает элемент в определённом состоянии или на определённом месте.
| Псевдокласс | Когда срабатывает |
|---|---|
:hover | Курсор над элементом |
:focus | Элемент получил фокус — например, после Tab |
:focus-visible | Фокус пришёл с клавиатуры. Именно его берут для обводки |
:active | Кнопку прямо сейчас нажимают |
:first-child | Элемент — первый ребёнок своего родителя |
:last-child | Последний ребёнок |
:nth-child(2) | Второй ребёнок |
:nth-child(odd) | Все нечётные — удобно для полосатых таблиц |
:not(.active) | Все, кроме тех, что подходят под скобки |
:checked | Включённый флажок или переключатель |
:disabled | Отключённое поле |
#nth-child: формула
В скобках у :nth-child() может стоять число, слово odd или even, а может — формула an + b.
:nth-child(3n)— каждый третий: 3, 6, 9…:nth-child(3n + 1)— первый в каждой тройке: 1, 4, 7…:nth-child(-n + 3)— первые три.
#Группировка и :is()
Одно правило можно повесить сразу на несколько селекторов, перечислив их через запятую. Запятая означает «или»: каждая часть работает сама по себе, и достаточно совпасть любой.
Когда общая у них только концовка, список быстро разрастается: .card h2, .card h3, .card h4. Псевдокласс :is() сворачивает такое перечисление в скобки — .card :is(h2, h3, h4). Читается короче, а ведёт себя так же.
/* Через запятую: каждый селектор пишется целиком */.card h2,.card h3,.card h4 { margin-block: 0 8px;}/* То же самое короче */.card :is(h2, h3, h4) { margin-block: 0 8px;}#:has() — селектор родителя
Долгие годы в CSS нельзя было выбрать элемент по его содержимому. Теперь можно: :has() выбирает элемент, внутри которого есть что-то определённое.
.card:has(img) { padding-top: 0;}/* Поле, у которого рядом отмечен флажок */label:has(input:checked) { font-weight: 700;}#Псевдоэлементы: то, чего нет в разметке
Псевдоэлемент пишется через два двоеточия и создаёт кусочек содержимого, которого в HTML нет. Самые ходовые — ::before и ::after.
Им обязательно нужно свойство content, даже пустое: без него элемент не появится.
Где спотыкаются почти все
Лишний пробел в селекторе
Почему a .btn вместо a.btn ищет потомка вместо самого элемента. Правило молча не срабатывает.
Как надо Нет пробела — «этот же элемент». Есть пробел — «внутри него».
Длинные цепочки вроде <code>body div.wrap ul li a span</code>
Почему Такое правило намертво привязано к структуре разметки: поменяешь один тег — всё развалится. И вес у него огромный, перекрыть почти невозможно.
Как надо Дай элементу класс и цепляйся за него: .menu__link.
Забыт content у псевдоэлемента
Почему Без content псевдоэлемент не создаётся вообще. Правило есть, эффекта нет.
Как надо Пиши content: ""; даже когда текст не нужен.
Стили только на :hover
Почему На телефоне наведения нет, а с клавиатуры приходит :focus. Кнопка, которая реагирует только на мышь, для половины людей неотличима от неактивной.
Как надо Пиши состояния группой: .btn:hover, .btn:focus-visible { … }.
- Селектор selector
- Выражение, описывающее, к каким элементам применить правило.
- Потомок descendant
- Любой элемент внутри другого, на любой глубине. Записывается пробелом.
- Прямой ребёнок child
- Элемент на один уровень внутри. Записывается знаком
>. - Псевдокласс pseudo-class
- Состояние или положение элемента:
:hover,:first-child. - Псевдоэлемент pseudo-element
- Виртуальный кусочек содержимого:
::before,::after.
Проверь себя
Пробел — «где-то внутри», знак <code>></code> — «непосредственно внутри, на один уровень».
Без пробела части относятся к одному элементу. Пробел означал бы «внутри», запятая — «или».
Без <code>content</code> псевдоэлемент не создаётся. Пустая строка тоже подходит: <code>content: "";</code>
<code>:nth-child(2)</code> — ровно вторая строка. <code>even</code> — все чётные.
Верных вариантов несколько.
<code>:hover</code> — для мыши, <code>:focus-visible</code> — для клавиатуры. <code>:visited</code> относится к посещённым ссылкам и к состоянию нажатия не имеет отношения.
Задание
Попасть шестью селекторами
В разметке шесть целей. Напиши шесть правил, не трогая HTML:
- всем пунктам списка — внутренний отступ не меньше 8px;
- только первому пункту — жирный шрифт;
- только последнему — убрать нижнюю границу (
border-bottom: none); - чётным пунктам — серый фон;
- ссылке с классом
btnпри наведении — другой цвет фона; - полю ввода в фокусе — видимая обводка через
:focus-visible.
Подсказка 1
Первый и последний выбираются так: .menu li:first-child и .menu li:last-child.
Подсказка 2
Чётные пункты: .menu li:nth-child(even) { background: #f4f4f8; }
Подсказка 3
Состояние наведения: .btn:hover { background: #5334cf; }. Обводка: input:focus-visible { outline: 3px solid #6544e0; }
Показать решение
<ul class="menu"> <li>Эспрессо</li> <li>Капучино</li> <li>Раф</li> <li>Флэт уайт</li></ul><p><a class="btn" href="#">Заказать</a></p><p><input type="text" aria-label="Комментарий к заказу"></p>.menu { max-width: 280px; padding: 0; list-style: none;}.menu li { padding: 10px 12px; border-bottom: 1px solid #ddd;}.menu li:first-child { font-weight: 700;}.menu li:last-child { border-bottom: none;}.menu li:nth-child(even) { background: #f4f4f8;}.btn { display: inline-block; padding: 10px 20px; color: #fff; background: #6544e0; border-radius: 999px; text-decoration: none;}.btn:hover { background: #5334cf;}input:focus-visible { outline: 3px solid #6544e0; outline-offset: 2px;}