CSS — селекторы и правила: практическое руководство

Основная идея: селекторы + декларации
CSS (Cascading Style Sheets) разделяет задачу на две части: что стилизовать (селектор) и как стилизовать (декларация — набор свойств и значений). Начать проще, если представить селектор как адрес DOM-элемента, а декларацию — как набор команд для этого адреса.
Ниже — систематизированное объяснение типов селекторов, примеры, рекомендации по специфичности, унаследованию и готовые шаблоны для практического использования.
Что такое селектор и декларация
- Селектор — часть правила, которая указывает, к каким элементам применить стиль (например, p, .intro, #header).
- Декларация — блок в фигурных скобках, содержащий свойства и значения (например, color: #333; margin: 0;).
Короткое определение: селектор — адрес, декларация — инструкция.
Уровни селекторов и поддержка браузеров
Исторически спецификация селекторов развивалась по уровням (Level 1, 2, 3 и далее). Многие возможности Level 3 давно доступны в современных браузерах. В 2020 году часть возможностей селекторов была доступна более чем 99% пользователей по данным Can I Use.
Важно: даже при широкой поддержке, некоторые новейшие псевдо-классы и синтаксис могут вести себя по-разному в старых версиях браузеров — всегда тестируйте критичные интерфейсы.
Level 1 — базовые селекторы (ключевые типы)
Level 1 ввёл четыре фундаментальных типа селекторов и базовые псевдо-классы/псевдоэлементы.
| Паттерн | Соответствует |
|---|---|
| E | всем элементам E |
| .c | всем элементам с class=”c” |
| #myid | элементу с id=”myid” |
| E F | элементу F внутри элемента E |
| Псевдо-классы | |
| E:link | ссылке, ещё не посещённой |
| E:visited | посещённой ссылке |
| E:active | ссылке в момент активации |
| Псевдоэлементы | |
| E::first-line | первая форматированная строка элемента E |
| E::first-letter | первая отформатированная буква элемента E |
Type Selector — селектор по типу
Простейший селектор: выбирает все элементы заданного типа.
p { margin-bottom: 0; }
b { font-family: sans-serif; }Class Selector — селектор по классу
Классы добавляют семантику элементам и позволяют повторно применять стили.
.intro { font-weight: bold; }Пример HTML, который он затронет:
…
…
Если нужен класс только для абзацев, комбинируйте с селектором типа:
p.intro { font-weight: bold; }ID Selector — селектор по id
Атрибут id должен быть уникален на странице. Используется для точечных целей.
…#contents { color: #333; }ID-селекторы очень специфичны — применять их к повторно используемым компонентам нежелательно.
Descendant Selector — селектор потомка
Этот селектор выбирает элементы по их контексту в дереве DOM.
table b { font-weight: normal; }Он найдёт все элементы b, находящиеся где-либо внутри table.
Псевдо-классы и псевдоэлементы
Псевдо-селекторы работают с «виртуальными» состояниями и частями элементов:
p::first-line { text-transform: uppercase; }Они удобны для добавления визуальных эффектов без лишней разметки.
Списки селекторов
Чтобы применить одно правило к нескольким селекторам, объединяйте их через запятую.
th, td { padding: 1em; }Это эквивалентно отдельным правилам для th и td, но компактнее.
Специфичность — как CSS выбирает правило
Когда несколько правил соответствуют одному элементу, побеждает правило с большей специфичностью. Упрощённая иерархия:
- ID-селекторы (#id) — самые специфичные.
- Классы, псевдоклассы и атрибутные селекторы (.class, :hover, [attr]) — средняя специфичность.
- Селекторы по типу и псевдоэлементы (div, p, ::before) — наименее специфичные.
Пример:
p.intro { color: black; }
p { color: gray; }В этом случае p.intro победит, потому что содержит селектор класса.
Правило при подсчёте специфичности: сначала считаются ID, затем классы/атрибуты/псевдоклассы, затем типы. Если на одном уровне есть равенство — сравнивают следующий уровень.
Важно избегать ненужного повышения специфичности (множественные id или цепочки классов), чтобы упрощать переопределение стилей.
Level 2 — новые возможности и комбинаторы
Level 2 расширил синтаксис, добавил атрибутные селекторы и новые комбинаторы.
| Паттерн | Соответствует |
|---|---|
| * | любому элементу |
| E > F | элементу F, являющемуся прямым потомком E |
| E + F | элементу F, который сразу следует за элементом E |
| Атрибутные селекторы | |
| E[foo] | элементу E с атрибутом “foo” |
| E[foo=”bar”] | элементу E с атрибутом foo, равным “bar” |
| E[foo~=”bar”] | атрибуту-списку, содержащему слово “bar” |
| E[foo|=”en”] | атрибуту, начинающемуся с “en-“ или точным “en” | | Псевдо-классы | | | E:first-child | элементу E, который первый у родителя | | E:lang(fr) | элементу E с языком fr | | Псевдоэлементы | | | E::before | сгенерированному контенту перед содержимым E | | E::after | сгенерированному контенту после содержимого E |
Универсальный селектор
* выбирает любой элемент. Часто используется для сброса стилей:
* { margin: 0; }Атрибутные селекторы
Позволяют таргетить элементы по наличию или значению атрибутов:
a[title] { text-decoration: underline dotted; }Комбинатор «прямой потомок» (>)
Выбирает только непосредственных детей, а не всех потомков.
ul > li { /* только первые уровни */ }Пример разницы:
- Section 1
- Section 1.1
- Section 2
ul > li выберет оба элемента li верхнего уровня, но не вложенные li внутри Section 1.
Селектор «сосед» (+)
E + F выбирает элемент F, который немедленно следует за E (следующий элемент-родной сосед).
h1 + p { font-weight: bold; }Важно: учитываются только элементы (element nodes), а не текстовые узлы.
Унаследованные свойства и стратегия применения
Некоторые CSS-свойства наследуются от родителя (например, font-family, color). Другие — нет (например, margin, padding). Это влияет на стратегию написания стилей:
- Устанавливайте общие значения на уровне body или корневых контейнеров, чтобы избежать повторов.
- Не пытайтесь заставить неунаследуемые свойства наследоваться — лучше выставить их явно там, где нужно.
Правило: выбирайте наименее специфичный селектор, который правильно решает задачу. Если достаточно задать font-family для body — не назначайте его для каждого абзаца.
Level 3 — дополнительные псевдо-классы, атрибуты и комбинатор
Level 3 добавил мощные возможности для позиционирования по порядку, атрибутным маскам и общим соседям.
| Паттерн | Соответствует |
|---|---|
| E ~ F | элементу F, который идёт после E среди соседей |
| Атрибутные селекторы | |
| E[foo^=”bar”] | атрибуту, начинающемуся с “bar” |
| E[foo$=”bar”] | атрибуту, заканчивающемуся на “bar” |
| E[foo*=”bar”] | атрибуту, содержащему подстроку “bar” |
| Псевдо-классы | |
| E:root | корневой элемент документа |
| E:nth-child(n) | n-й ребёнок родителя |
| E:nth-last-child(n) | n-й ребёнок, считая с конца |
| E:nth-of-type(n) | n-й среди однотипных соседей |
| E:last-child | последний ребёнок |
| E:first-of-type | первый среди однотипных соседей |
| E:last-of-type | последний среди однотипных соседей |
| E:only-child | единственный ребёнок родителя |
| E:only-of-type | единственный в своём типе |
| E:empty | не содержит дочерних узлов, включая текст |
| E:target | элемент, на который указывает фрагмент URI (#id) |
| E:enabled | включённый элемент формы |
| E:disabled | отключённый элемент формы |
| E:checked | отмеченный элемент формы (checkbox/radio) |
| E:not(s) | элемент E, который не соответствует простому селектору s |
Примеры атрибутных селекторов
- Элементы, href которых начинается с https:
a[href^="https:"] { /* безопасные ссылки */ }- Изображения с расширением .gif:
img[src$=".gif"] { /* стили для гифок */ }- Атрибуты, содержащие подстроку:
a[href*="example"] { /* содержит example */ }Псевдо-классы для позиционирования и выбора по порядку
:nth-child() и родственные классы мощны, но их следует использовать осторожно: изменения DOM (добавление/удаление элементов) могут изменить выборку и повести стили непредсказуемо.
Общий сосед (~)
h1 ~ p { font-size: 110%; } — выберет все p, которые идут после h1 среди его соседей, а не только ближайший.
Практическая шпаргалка — какой селектор использовать
- Для глобальных правил: body, html, :root
- Для компонентных стилей: классы (.card, .btn)
- Для уникальных контейнеров: id (редко, только если действительно уникально)
- Для структуры: комбинируйте type + class (ul.menu > li)
- Для динамических состояний: псевдоклассы (:hover, :focus, :checked)
- Для генерации контента: ::before, ::after
Когда селекторы подводят: типичные ошибки и контрпримеры
- Слишком высокая специфичность:
- Проблем: трудно переопределять стиль, копится “!important”.
- Контрпример: вместо #header .nav li a лучше .nav__link.
- Зависимость от порядка DOM для :nth-child():
- Проблем: добавление скрытых элементов ломает визуал.
- Контрпример: использование классов для стабильности.
- Универсальный сброс (*) приводит к проблемам производительности на больших документах.
- Атрибутные селекторы со сложными выражениями могут быть медленнее — используйте их там, где это оправдано.
Альтернативные подходы к выбору элементов
- БЭМ-методология: нейминг классов по блокам, элементам и модификаторам (.block__elem–mod) — снижает конфликты.
- CSS-in-JS: локализует стили внутри компонентов (React, Vue), но добавляет зависимость от сборки.
- Utility-first (например, Tailwind): избегает семантических классов, быстро прототипируется, но может усложнить читабельность HTML.
Каждый подход имеет компромиссы — выбирайте в зависимости от команды, масштаба проекта и требований к поддержке.
Методика выбора селектора — мини-шаги
- Определите гранулярность: глобально, компонентно или локально.
- Проверьте, можно ли решить задачу простым классом.
- Применяйте наименее специфичный селектор, достаточный для задачи.
- Избегайте id и !important в стилях компонентов.
- Тестируйте изменения в разных состояниях и при изменении DOM.
Decision tree — как выбрать селектор (Mermaid)
flowchart TD
A[Нужно изменить внешний вид элемента?] --> B{Уникальный элемент?}
B -- Да --> C[Используйте id или уникальный класс]
B -- Нет --> D{Это повторяющийся компонент?}
D -- Да --> E[Используйте класс по БЭМ/компоненту]
D -- Нет --> F{Требуется зависимость от структуры DOM?}
F -- Да --> G[Используйте комбинированные селекторы 'type + class или >, +, ~']
F -- Нет --> H[Используйте простой селектор по типу или класс]
C --> I[Проверьте специфичность и тестируйте]
E --> I
G --> I
H --> IЧеклист по ролям
- Дизайнер:
- Укажите семантику классов для интерактивных состояний.
- Согласуйте глобальные переменные цвета/типографики.
- Фронтенд-разработчик:
- Используйте классы для компонентов, избегайте id.
- Документируйте соглашения по неймингу (БЭМ/atomic).
- Тестировщик/QA:
- Проверяйте вёрстку при динамическом добавлении/удалении элементов.
- Тестируйте фокус/переходы и отвечающие состояния (keyboard nav).
SOP: рефакторинг селекторов в крупном проекте
- Найдите повторяющиеся цепочки селекторов.
- Введите компонентные классы и переведите стили постепенно.
- Запустите визуальные регрессионные тесты (snapshot, Percy, Chromatic).
- Удалите устаревшие правила после проверки.
- Обновите документацию стилей и примеры использования.
Критерии приёмки
- Изменение внешнего вида достигается без !important и без изменения id.
- Все браузерные тесты проходят (основные версии Chrome, Firefox, Safari, Edge).
- Нет конфликтов специфичности с существующими компонентами.
- Компонентную стилизацию можно переиспользовать в других местах.
Тест-кейсы и приёмочные сценарии
- Добавление нового элемента в середину списка — проверка :nth-child и соседей.
- Изменение порядка DOM — проверка селекторов по структуре (>, +, ~).
- Отключение стилей на мобильных — проверка медиа-запросов и адаптивных селекторов.
- Переходы между состояниями :hover/:focus — проверка доступности и клавиатурной навигации.
Шпаргалка свойств специфичности (быстрая)
- ID (#id): высокий приоритет.
- Классы/атрибуты/псевдоклассы (.class, [attr], :hover): средний.
- Типы/псевдоэлементы (div, p, ::before): низкий.
- Inline-стили (style=”…”) обычно имеют очень высокий приоритет.
Глоссарий в одну строчку
- Селектор: выражение, определяющее набор элементов.
- Декларация: набор свойств в фигурных скобках.
- Комбинатор: символ, описывающий взаимосвязь между селекторами (>, +, ~, пробел).
- Псевдо-класс: состояние элемента (:hover, :checked).
- Псевдо-элемент: виртуальная часть элемента (::before).
Совместимость и миграция
- Проверяйте старые браузеры, если ваша аудитория использует устаревшие версии.
- При миграции к компонентной архитектуре переводите правила постепенно и покрывайте тестами.
- Рассмотрите использование постпроцессоров (PostCSS) для трансформации современных синтаксисов в совместимые.
Примечания по доступности и приватности
- Используйте :focus-visible или :focus для видимой навигации клавиатурой.
- Псевдоэлементы не должны использоваться для критического контента, который недоступен скринридерам.
Когда не использовать селекторы (альтернативы)
- Если элемент управляется логикой приложения — используйте динамические классы из JS вместо сложного CSS-поиска.
- Если нужно уникальное поведение — рассмотрите inline-стиль, но избегайте его для повторяемых случаев.
Шаблоны и примеры (cheat sheet)
- Сброс отступов для таблиц:
table, th, td { border-collapse: collapse; }- Карточка компонента (пример структуры классов):
.card { background: #fff; border-radius: 6px; }
.card__title { font-size: 1.25rem; }
.card--featured { box-shadow: 0 4px 12px rgba(0,0,0,0.08); }- Акцент на ссылки внутри меню:
.nav__link:hover, .nav__link:focus { text-decoration: underline; }Краткое объявление для команды (100–200 слов)
Мы запускаем обновление архитектуры CSS: перейдём на компонентный подход с единым соглашением по неймингу (БЭМ). Цель — уменьшить количество конфликтов селекторов и упростить повторное использование стилей. План: 1) ввод новых компонентных классов, 2) поэтапный перенос правил и 3) визуальное тестирование. Обновлённая документация и чеклисты будут доступны в репозитории. Просят всех разработчиков согласовывать изменения и добавлять юнит/визуальные тесты для новых компонентов.
Часто задаваемые вопросы
Как выбрать между классом и id?
Класс лучше для повторяющихся и переиспользуемых компонентов. ID — только для уникальных элементов, когда нужна точечная идентификация.
Можно ли полагаться на :nth-child в крупных проектах?
Только если структура стабильна. Для динамических списков лучше использовать классы для стабильности.
Как упростить специфичность в большом кодовой базе?
Введи соглашение по неймингу (например, БЭМ), минимизируй глубину вложенности селекторов и избегай id в стилях.
Итог: понимание селекторов — это базовый навык для любой вёрстки. Начните с простых классов и типов, осваивайте псевдо-классы и атрибутные селекторы по мере необходимости, и всегда следите за специфичностью и поддерживаемостью.
Важно: перед массовыми изменениями стилей прогоняйте визуальные регрессионные тесты и согласуйте стандарты с командой.
Похожие материалы
Как распознать поддельное приложение ChatGPT в App Store
Сброс Windows 10/11 без потери файлов
Исправление ошибок VLOOKUP в Excel
Как удалить файлы и папки в Linux
Сорванный винт в электронике — как аккуратно выкрутить