Урок 12. Теория: Каскад, наследование и специфичность

📁 Раздел: Основы CSS ⏱️ Время изучения: ~45 мин 🎯 Сложность: Начальная
#p #hover #style

⚡ Кратко

Когда несколько правил спорят за одно свойство одного элемента, браузер выбирает победителя по чёткому алгоритму.

  • Специфичность — главный судья. Считается как четыре разряда (inline, id, class, tag): style="" > #id > .class > тег.
  • Порядок решает только при равной специфичности: побеждает правило, написанное ниже.
  • Наследование: color, font-family, font-size переходят к детям; margin, padding, border — нет.
  • !important перебивает обычную специфичность, но на базовом уровне это «красная кнопка» — почти всегда лучше упростить селекторы.

Главная идея

CSS называется каскадным (cascade — «водопад»), потому что итоговое значение каждого свойства «стекает» сверху вниз через множество конкурирующих правил, и до элемента доходит только одно — победитель. Когда на один и тот же color претендуют сразу три правила, браузер не гадает: он сравнивает их по строгому алгоритму. Понять этот алгоритм — значит перестать удивляться, почему «мой цвет не применяется».

Специфичность — это воинские звания. Представь, что правила CSS — солдаты, которые спорят, какого цвета красить стену. Селектор по тегу (p) — рядовой. Класс (.text) — сержант. Идентификатор (#lead) — офицер. А inline-стиль (style="...") — генерал. Приказ генерала отменяет приказ офицера, офицера — приказ сержанта и так далее. Если же спорят двое одного звания — слушают того, кто заговорил последним (правило ниже в коде). А !important — это маршал, который перебивает любого… но злоупотреблять им — значит развязать «войну званий».

Как считается специфичность

Специфичность записывают как четыре числа (a, b, c, d) — четыре разряда, от старшего к младшему. Браузер сравнивает их как версии ПО: сначала a, при равенстве — b, и так далее. Важно: разряды не переносятся — десять классов (0,0,10,0) всё равно слабее одного id (0,1,0,0).

inline #id .class тег p 0 0 0 1 .text 0 0 1 0 .card p 0 0 1 1 #lead 0 1 0 0 style="…" 1 0 0 0
Каждый селектор раскладывается на разряды (inline, id, class, tag). Сравнение идёт слева направо: чем левее ненулевой разряд, тем сильнее правило.

Подсчёт на примерах:

  • p → один тег → (0,0,0,1)
  • .text → один класс → (0,0,1,0) — сильнее любого числа тегов
  • .card p → класс + тег → (0,0,1,1)
  • #lead → один id → (0,1,0,0) — сильнее любого числа классов
  • style="color:red" (inline) → (1,0,0,0) — сильнее любого id
Псевдоклассы считаются как класс (:hover, :first-child → разряд class), а псевдоэлементы (::before) — как тег. Универсальный селектор * специфичности не добавляет.

Порядок и наследование

Если у двух правил специфичность одинаковая — спор решает порядок: побеждает то, что ниже в коде (а при подключении нескольких файлов — то, что подключено позже). Поэтому в командах принято держать «общее → частное» сверху вниз.

.button { background: #e5e7eb; }
.button { background: #0f766e; } /* специфичность та же → побеждает это, оно ниже */

Отдельно от спора правил работает наследование: некоторые свойства ребёнок берёт у родителя «по умолчанию». Наследуются в основном текстовые свойства (color, font-family, font-size, line-height), а размеры и рамки (margin, padding, border, width) — нет. Управлять этим явно помогают значения inherit, initial, unset.

Зачем это знать

90% ситуаций «стиль не применился» — это не баг браузера, а проигрыш по специфичности или порядку. Открыв DevTools (F12), вы увидите перечёркнутые объявления — это и есть проигравшие правила. Понимая каскад, вы пишете предсказуемый CSS на классах с низкой специфичностью и почти никогда не доходите до !important.

Про !important: он перебивает обычную специфичность, но создаёт «войну ставок» — следующий разработчик вынужден добавлять ещё один !important. На базовом уровне его лучше не использовать вовсе.
Проверка понимания: откройте пример из раздела «Примеры», посчитайте специфичность каждого правила и предскажите цвет до запуска браузера.