Что такое CSS: селекторы, каскад и специфичность
Основы3 минРедакция Innovialabs
Коротко
CSS — язык оформления: селектор выбирает элементы, правило задаёт стили, а при конфликте побеждает объявление с более высокой специфичностью или, при равенстве, последнее в коде.
Что такое CSS и как он работает
CSS (Cascading Style Sheets) описывает, как выглядят элементы HTML: цвета, шрифты, отступы, расположение. HTML отвечает за структуру, CSS — за внешний вид.
Каждое правило состоит из селектора и объявлений:
p {
color: #333;
line-height: 1.6;
}
p — селектор (все абзацы), color: #333 — объявление «свойство: значение». Браузер читает HTML, строит дерево элементов, находит для каждого все подходящие правила и вычисляет итоговые стили.
Основные селекторы
| Селектор | Пример | Что выбирает |
|---|---|---|
| По тегу | p | Все абзацы |
| По классу | .card | Элементы с class="card" |
| По id | #logo | Элемент с id="logo" |
| По атрибуту | [type="email"] | Поля с этим типом |
| Потомок | .card p | Абзацы внутри .card |
| Прямой потомок | ul > li | Только дочерние li |
| Псевдокласс | a:hover | Ссылка под курсором |
На практике основа вёрстки — классы. Они переиспользуются и не создают проблем со специфичностью.
Каскад: что делать, если правил несколько
Одному элементу часто подходит несколько правил с одинаковым свойством. Браузер решает конфликт по порядку:
- Источник и важность. Стили автора сайта перекрывают стили браузера по умолчанию.
!importantподнимает приоритет объявления. - Специфичность. Более точный селектор побеждает.
- Порядок в коде. При равной специфичности побеждает правило, объявленное позже.
.title { color: blue; }
.title { color: red; } /* победит: объявлено позже */
Специфичность простыми словами
Специфичность считается как три числа: id — классы — теги.
| Селектор | Специфичность |
|---|---|
p | 0-0-1 |
.card p | 0-1-1 |
.card .title | 0-2-0 |
#main .title | 1-1-0 |
Сравнение идёт слева направо: один id сильнее любого количества классов. К «классам» относятся также атрибуты и псевдоклассы, к «тегам» — псевдоэлементы вроде ::before. Инлайн-стиль style="..." сильнее любого селектора.
<p id="intro" class="lead">Текст</p>
#intro { color: green; } /* 1-0-0, победит */
.lead { color: blue; } /* 0-1-0 */
p { color: gray; } /* 0-0-1 */
Наследование
Часть свойств наследуется от родителя: color, font-family, font-size, line-height. Поэтому шрифт достаточно задать на body.
Другие свойства не наследуются: margin, padding, border, background, width. Принудительно унаследовать значение можно через inherit:
button { font: inherit; }
Блочная модель
Каждый элемент — прямоугольник из четырёх слоёв: content (содержимое), padding (внутренний отступ), border (рамка), margin (внешний отступ).
По умолчанию width задаёт только ширину содержимого, а padding и border добавляются сверху. Поэтому блок width: 300px; padding: 20px на деле занимает 340px. Большинство проектов меняют это поведение:
*, *::before, *::after {
box-sizing: border-box;
}
Теперь width включает padding и border, и размеры считать проще.
Частые ошибки
- Борьба через
!important. Это временно гасит конфликт, но следующий!importantпридётся перебивать снова. Лучше упростить селекторы. - Стилизация по id. Высокая специфичность мешает потом переопределять стили.
- Длинные цепочки вроде
.page .content .list .item a. Они хрупкие и зависят от разметки. - Забытый
box-sizing, из-за которого блоки не помещаются в сетку.
Понять, какое правило применилось, помогает вкладка Styles в DevTools: перечёркнутые объявления проиграли каскад. Подробный справочник — на MDN.