Специфичность селекторов
Специфичность определяет, какой CSS-правило применится при конфликте стилей. Понимание специфичности помогает избежать !important.
Что такое специфичность?
Когда несколько CSS-правил применяются к одному элементу и задают одно свойство, браузер выбирает наиболее специфичное правило.
p { color: black; } /* Специфичность: 0-0-1 */
.text { color: blue; } /* Специфичность: 0-1-0 */
#main p { color: red; } /* Специфичность: 1-0-1 */
<p id="main" class="text">Какого цвета текст?</p>
<!-- Ответ: красного — выигрывает #main p -->
Как считается специфичность
Специфичность записывается как три числа A-B-C:
| Категория | Значение A | Пример |
|---|---|---|
| ID | +1-0-0 | #header |
| Класс, атрибут, псевдокласс | +0-1-0 | .btn, [type], :hover |
| Тег, псевдоэлемент | +0-0-1 | div, ::before |
* универсальный | 0-0-0 | * |
div /* 0-0-1 */
.btn /* 0-1-0 */
#app /* 1-0-0 */
div.btn /* 0-1-1 */
#app .btn /* 1-1-0 */
#app .list > .item /* 1-2-0 */
button:hover /* 0-1-1 */
input[type="text"] /* 0-1-1 */
::before /* 0-0-1 */
Сравнение идёт слева направо: 1-0-0 всегда больше 0-99-99.
Инлайн-стили и !important
<!-- Инлайн-стили имеют специфичность 1-0-0-0 (выше ID) -->
<p style="color: green;">Текст</p>
/* !important побеждает всё, включая инлайн-стили */
p { color: red !important; }
Иерархия (от слабого к сильному):
- Браузерные стили по умолчанию
- Таблицы стилей автора
- Инлайн-стили
!important
Порядок источников
При одинаковой специфичности побеждает последнее объявление:
.btn { color: blue; }
.btn { color: red; } /* Это правило применится */
/* Порядок подключения стилей важен */
@import 'reset.css';
@import 'components.css'; /* Переопределяет reset.css при равной специфичности */
Практические советы
1. Держите специфичность низкой
/* Плохо — высокая специфичность */
#sidebar .nav-list li a.active { color: violet; }
/* Лучше — добавить класс прямо на элемент */
.nav-link-active { color: violet; }
2. Избегайте !important
/* !important создаёт «долг специфичности» */
.title { color: red !important; }
/* Потом придётся бороться: */
.header .title { color: blue !important; } /* Перебить не получится без ещё одного !important */
Исключение — утилитарные классы (как Tailwind), где !important обосновано.
3. Используйте () для нулевой специфичности
/* :where() имеет специфичность 0-0-0 */
:where(.card, .panel) p { color: gray; }
/* :is() сохраняет специфичность наибольшего аргумента */
:is(#app, .container) p { color: blue; } /* 1-0-1 из-за #app */
4. Слои (@layer)
CSS-слои позволяют явно управлять порядком без !important:
@layer reset, base, components, utilities;
@layer reset {
* { margin: 0; padding: 0; }
}
@layer components {
.btn { background: blue; } /* Переопределяет reset */
}
@layer utilities {
.hidden { display: none; } /* Переопределяет всё выше */
}
Отладка специфичности
В DevTools браузера зачёркнутые правила — это переопределённые стили. Наведите на селектор — увидите его специфичность в tooltip.
Инструменты для расчёта: specificity.keegan.st