Главная идея
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).
Подсчёт на примерах:
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.
На базовом уровне его лучше не использовать вовсе.