Калькулятор специфичности CSS
СправочникВычисляет специфичность (A, B, C) любого CSS-селектора — ID, классы, атрибуты, псевдоклассы и элементы — сравнивает несколько селекторов сразу и показывает вклад каждой части. Поддерживает :is(), :not() и :where().
На этой странице
Что такое специфичность CSS?#
Когда два CSS-правила пытаются установить одно свойство одного элемента, браузер выбирает не написанное последним — он выбирает с большей специфичностью. Специфичность — это трёхчастный счётчик (A, B, C), который каскад сравнивает как номер версии:
- A — ID-селекторы (
#header). - B — селекторы классов (
.btn), атрибутов ([type=email]) и псевдоклассов (:hover,:focus). - C — селекторы типов (
div,a) и псевдоэлементы (::before,::first-line).
A сравнивается первым; при ничьей спуск к B, затем C. Один ID (1,0,0) бьёт любое число классов (0,99,99), которые, в свою очередь, бьют любое число типов. Универсальный *, комбинаторы (> + ~) и вложенный селектор & ничего не добавляют.
Эта страница вычисляет этот кортеж для любого селектора, который вы вставите, — включая современные функциональные псевдоклассы :is(), :where(), :not(), :has() и предложение of S у :nth-child(), — ранжирует список селекторов и показывает, какие части что внесли. Это самый быстрый способ ответить на универсальный CSS-вопрос: «почему моё правило проигрывает?»
Как пользоваться#
- Нажмите Пример, чтобы загрузить готовый набор селекторов, или очистите поле и вставьте свой. Можно ввести одиночный селектор (
#nav .item) или целое правило (#nav .item { color: red }); инструмент читает часть до{. - Несколько селекторов? Разделите их запятыми — они ранжируются от наиболее к наименее специфичным, победитель помечается.
- Правая панель перечисляет каждый селектор с кортежем
(A, B, C)и цветной разбивкой каждой вкладывающей части (красный = ID, синий = класс/атрибут/псевдокласс, зелёный = тип/псевдоэлемент), поэтому видно, почему счёт именно такой. - Цветная легенда в правом верхнем углу напоминает, какая точка соответствует A / B / C.
- Если ваше правило содержало
!important, появится информационная заметка —!importantэто переопределение на уровне объявления, сидящее выше сравнения специфичности, а не внутри него.
Ключевые возможности#
- Корректность на сложных случаях.
:where()всегда вносит(0,0,0);:is()/:not()/:has()берут наивысшую специфичность среди аргументов; Legacy:beforeи предложениеof Sу:nth-child()обрабатываются по Selectors Level 4. - Ранжирует список через запятую и помечает ничьи, поэтому с одного взгляда видно, какое из нескольких правил победит.
- Разбивка по частям. Каждый
#id,.class,[attr],:псевдокласс,::псевдоэлементи тип перечислены с точным текстом, который они внесли. - Толерантен к полным правилам. Вставьте
a:hover { text-decoration: underline }— комментарии вырезаются, а блок объявлений игнорируется автоматически. - 100 % локально. Ничего не покидает страницу; никакая таблица стилей не запрашивается и не вычисляется.
Разбор примера#
Частая головоломка отладки: три правила нацелены на одну ссылку, и побеждает неправильный цвет. Вставьте их в поле:
.button:hover
:is(.card, #hero) .button
a.button
Вывод ранжирует их:
| Ранг | Селектор | Кортеж |
|---|---|---|
| 1 | :is(.card, #hero) .button | (1, 1, 0) — победитель |
| 2 | .button:hover | (0, 2, 0) |
| 3 | a.button | (0, 1, 1) |
Победитель — не тот, у кого больше классов. :is(.card, #hero) наследует наивысшую специфичность своих аргументов — #hero это ID, поэтому :is() несёт (1,0,0), хотя .card был бы лишь (0,1,0). Добавление .button увеличивает B на единицу, давая (1,1,0). Этот единственный ID в колонке A бьёт два класса у .button:hover (0,2,0) — то самое удивление, которое делает :is() опасным в продакшен-CSS.
Если нужно такое же группирование без роста специфичности, поменяйте :is() на :where():
:where(.card, #hero) .button → (0, 1, 0)
Теперь это ничья с a.button минус тип, и порядок в источнике решает. Это единственная причина существования :where().
FAQ#
Почему один ID бьёт сотни классов?#
Специфичность сравнивает колонки слева направо как номер версии, а не как сумму. (1,0,0) «впереди» (0,999,999), потому что в первой колонка A ненулевая, а во второй ноль; колонки B и C даже не опрашиваются. Это намеренно — ID задумывались как однозначные синглтоны.
В чём разница между :is() и :where()?#
Они идентичны в том, что матчат, но противоположны по специфичности. :is(.a, #b) берёт наивысшую специфичность среди аргументов (поэтому #b делает её (1,0,0)); :where(.a, #b) всегда вносит (0,0,0) независимо от аргументов. Используйте :where() для низкоспецифичных дефолтов, которые легко переопределить, и :is(), когда вы действительно хотите, чтобы составной селектор конкурировал.
Атрибут inline style="…" бьёт эти?#
Да. Inline-стили превосходят любое селекторное правило в обычном каскаде (они сидят в более высоком origin), поэтому никакой селекторный кортеж не перекроет inline-стиль без !important. Это отдельная ось от счёта (A,B,C), поэтому инструмент оценивает только селекторы.
Куда попадает !important?#
!important — флаг на уровне объявления, а не свойство селектора; он не меняет кортеж (A,B,C). Он переносит всё объявление в более высокий cascade origin, поэтому правило с !important бьёт обычное независимо от специфичности. Инструмент информационно отмечает его присутствие, но в счёт не включает.