Калькулятор специфичности CSS
Впишите CSS-селекторы по одному в строке — калькулятор разберёт каждый на части, посчитает специфичность (a,b,c) и покажет, какое правило победит.
/* #nav .item a → (1,1,1) */
/* .nav .item a:hover → (0,3,1) */
/* nav ul li a → (0,0,4) */
/* winner: #nav .item a → (1,1,1) */
Как пользоваться
- Введите по одному селектору в строке (до 10 строк) или выберите готовый пример.
- Посмотрите цветной разбор: красным выделен
a(ID), синимb(классы, атрибуты, псевдоклассы), зелёнымc(теги, псевдоэлементы). - Сравните значки
(a,b,c): сначала сравниваетсяa, при равенствеb, затемc. Селектор на первом месте рейтинга побеждает. - При полном равенстве побеждает правило, написанное в CSS позже.
!important, inline-стили и@layerучитываются отдельно.
Как это работает
Три числа (a,b,c)
Специфичность состоит из трёх столбцов. a — количество ID-селекторов (#id), b — классов (.class), атрибутов ([type]) и псевдоклассов (:hover), c — тегов (div) и псевдоэлементов (::before). Сравнение идёт слева направо: один ID сильнее любого числа классов, а одиннадцать тегов никогда не перебьют один класс — столбцы не переносятся друг в друга.
#nav .item a → (1,1,1)
.nav .item a:hover → (0,3,1)
nav ul li a → (0,0,4)
Что считается, а что нет
Универсальный селектор *, комбинаторы (пробел, >, +, ~) и :where() дают 0. Атрибутный селектор [id="x"] — это атрибут, а не ID, поэтому он идёт в столбец b. Старые псевдоэлементы с одним двоеточием — :before, :after, :first-line, :first-letter — считаются псевдоэлементами и попадают в c.
:is(), :not(), :has() и :where()
:is(), :not() и :has() сами ничего не добавляют, но берут специфичность самого сильного аргумента из списка: :is(#a, .b) равно (1,0,0). :where() всегда равен нулю, поэтому он удобен для сбросов и базовых стилей, которые должны легко переопределяться. :nth-child(2n+1 of .x) — это псевдокласс (b) плюс специфичность селектора .x.
Специфичность — не весь каскад
Каскад сначала смотрит на происхождение стиля и !important, затем на стили, привязанные к элементу (inline), потом на слои @layer и только после этого сравнивает специфичность; последним решает порядок записи. Поэтому style="..." и !important перебивают обычное правило независимо от веса селектора, а правило из более позднего слоя побеждает более сильный селектор из раннего. У !important порядок слоёв переворачивается.
@layer base, components;
@layer base { #page p { color: red; } }
@layer components { p { color: blue; } }
/* побеждает components: слой объявлен позже */
Частые вопросы
Почему моё правило не применяется, хотя оно ниже в файле?
Порядок записи решает только при равной специфичности. Скорее всего, у другого правила селектор сильнее. Впишите оба селектора в калькулятор и сравните, затем проверьте !important, inline-стили и @layer.
Меняет ли !important специфичность?
Нет. !important — отдельный этап каскада: важное объявление сильнее обычного, а между несколькими важными снова решают специфичность и порядок. Чем писать !important, лучше упростить селектор или вынести стили в @layer.
Могут ли много классов победить один ID?
Нет. Столбец a сравнивается раньше b, поэтому даже сто классов не перебьют один ID: (1,0,0) сильнее любого (0,N,M). Зато (0,2,0) сильнее (0,1,5).
Участвует ли в сравнении унаследованное значение?
Нет. Любое правило, которое напрямую попало в элемент, — даже с селектором * и нулевой специфичностью — сильнее значения, унаследованного от родителя.