Инструменты
Руководства

Калькулятор специфичности CSS

Справочник

Вычисляет специфичность (A, B, C) любого CSS-селектора — ID, классы, атрибуты, псевдоклассы и элементы — сравнивает несколько селекторов сразу и показывает вклад каждой части. Поддерживает :is(), :not() и :where().

100 % на клиенте Без бэкенда
ID-селекторы (A) Классы, атрибуты и псевдоклассы (B) Элементы и псевдоэлементы (C)
Селектор Специфичность (A, B, C)
Вклад
Введите один или несколько CSS-селекторов для расчёта специфичности.
На этой странице

Что такое специфичность 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-вопрос: «почему моё правило проигрывает?»

Как пользоваться#

  1. Нажмите Пример, чтобы загрузить готовый набор селекторов, или очистите поле и вставьте свой. Можно ввести одиночный селектор (#nav .item) или целое правило (#nav .item { color: red }); инструмент читает часть до {.
  2. Несколько селекторов? Разделите их запятыми — они ранжируются от наиболее к наименее специфичным, победитель помечается.
  3. Правая панель перечисляет каждый селектор с кортежем (A, B, C) и цветной разбивкой каждой вкладывающей части (красный = ID, синий = класс/атрибут/псевдокласс, зелёный = тип/псевдоэлемент), поэтому видно, почему счёт именно такой.
  4. Цветная легенда в правом верхнем углу напоминает, какая точка соответствует A / B / C.
  5. Если ваше правило содержало !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)
3a.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 бьёт обычное независимо от специфичности. Инструмент информационно отмечает его присутствие, но в счёт не включает.