Тренажёр специфичности и каскада CSS
Специфичность — это вес CSS-селектора, который помогает определить, какое правило применится к элементу при прочих равных условиях каскада. Но вес — не единственное, что решает спор. В тренажёре два раздела: сначала задания на специфичность селекторов, затем на весь каскад — порядок правил, !important, атрибут style, слои и наследование.
Как пользоваться
- Выберите задание в списке или переходите стрелками. Счётчик показывает номер текущего задания.
- Посмотрите на HTML и CSS и выберите, каким будет цвет текста элемента
<p>. Под каждым цветом подписано, откуда он может прийти: из какого правила, атрибутаstyleили от родителя. - После верного ответа прочитайте объяснение. Если ошиблись, правильный ответ не раскрывается — попробуйте снова.
- Счётчик решённых заданий показывает прогресс. Кнопка со стрелкой по кругу сбрасывает его. Решённые задания отмечаются галочкой. Прогресс сохраняется в этом браузере между посещениями, если доступно локальное хранилище.
Как устроена специфичность
Сначала сравниваются идентификаторы, затем классы, атрибуты и псевдоклассы, затем типы и псевдоэлементы. Комбинаторы и универсальный селектор веса не добавляют. При равном весе и прочих равных условиях побеждает более позднее правило.
:is(), :not() и :has() берут максимальный вес аргументов; :where() всегда даёт ноль. Для :nth-child(... of ...) вес аргументов прибавляется к весу псевдокласса.
Специфичность — только один этап каскада. Сначала учитываются происхождение, важность и слои; при равном весе также может учитываться близость области @scope.
Продолжить: Разобрать свой селектор, тренажёр селекторов, каскадность в CSS. Правила расчёта: спецификация Selectors.
Как браузер выбирает значение
Если к элементу подходят несколько объявлений одного свойства, браузер сравнивает их по этапам и останавливается на первом, где нашлась разница:
- Важность. Объявление с
!importantсильнее обычного. - Атрибут
style. Обычный inline-стиль сильнее обычных правил из таблицы стилей, но слабее их!important. - Слои
@layer. Более поздний слой сильнее, стили вне слоёв сильнее всех слоёв. Для!importantпорядок переворачивается. - Специфичность селектора.
- Близость
@scope. Побеждает правило, чей корень области ближе к элементу. - Порядок в коде. Последнее объявление побеждает.
Наследование в этом споре не участвует: унаследованное значение используется, только если к самому элементу не подошло ни одно объявление этого свойства. Значение inherit явно просит взять значение родителя.
Тренажёр
Определите, каким цветом будет текст элемента <p>.
Правила записаны в одной таблице стилей сверху вниз, без анимаций и переходов. В разделе «Специфичность» оба селектора подходят к элементу, а !important, слоёв и inline-стилей нет. В разделе «Каскад» в игру вступают они, а также наследование и @scope.
<p class="note">Текст</p>.note { color: red; }
p { color: blue; }<p class="note active" id="target">Текст</p>#target { color: red; }
.note.active { color: blue; }<p class="active note">Текст</p>.note { color: red; }
.active { color: blue; }<div><div><p class="note">Текст</p></div></div>div div p { color: red; }
.note { color: blue; }<div class="card"><p>Текст</p></div>.card * { color: red; }
p { color: blue; }<p id="target">Текст</p>[id="target"] { color: red; }
#target { color: blue; }<div><p class="note">Текст</p></div>p:first-child { color: red; }
.note { color: blue; }<p lang="ru">Текст</p>:lang(ru) { color: red; }
p { color: blue; }<div><h2>Заголовок</h2><p class="note">Текст</p></div>h2 + p { color: red; }
.note { color: blue; }<p id="target">Текст</p>:where(#target) { color: red; }
p { color: blue; }<p class="note active">Текст</p>:is(.note, #unused) { color: red; }
.note.active { color: blue; }<p class="note">Текст</p>p:not(#unused) { color: red; }
.note { color: blue; }<p class="note">Текст <span class="badge">!</span></p>p:has(> .badge) { color: red; }
.note { color: blue; }<p class="note">Текст</p>:nth-child(1 of .note) { color: red; }
.note { color: blue; }<p data-note class="note">Текст</p>[data-note] { color: red; }
.note { color: blue; }<div><p>Текст</p></div>div > p { color: red; }
div p { color: blue; }<p class="note" id="target">Текст</p>:is(:where(#target), .note) { color: red; }
p.note { color: blue; }<p class="a" id="target">Текст</p>#target { color: red; }
.a.a.a.a.a.a.a.a.a.a.a { color: blue; }<p>Текст</p>:is(p, div, section, article) { color: red; }
p { color: blue; }<p id="target">Текст</p>p:not(.a, #b) { color: red; }
#target { color: blue; }<p class="note active">Текст</p>.note:where(.active) { color: red; }
p.note { color: blue; }<p class="note" id="target">Текст</p>#target#target { color: red; }
#target.note { color: blue; }<p class="note">Текст <span id="icon">!</span></p>.note { color: red; }
p:has(#icon) { color: blue; }<div><p class="note">Текст</p></div>p:nth-of-type(1) { color: red; }
p:nth-child(1 of .note) { color: blue; }<p>Текст</p>p { color: red; }
p { color: blue; }<p class="note">Текст</p>.note { color: red; }
p.note { color: green; }
.note { color: blue; }<div id="box">
<p>Текст</p>
</div>#box { color: red; }
* { color: blue; }<div class="card">
<p>Текст <span>!</span></p>
</div>.card { color: red; }
p span { color: blue; }<div class="card">
<p class="note">Текст</p>
</div>.card { color: red; }
p { color: blue; }
.note { color: inherit; }<p class="note" id="target">Текст</p>p { color: red !important; }
#target.note { color: blue; }<p class="note" id="target" style="color: green">Текст</p>#target { color: red; }
.note { color: blue; }<p style="color: green">Текст</p>p { color: red !important; }<p class="note" id="target">Текст</p>#target { color: red !important; }
.note { color: blue !important; }<p id="target">Текст</p>@layer base {
#target { color: red; }
}
p { color: blue; }<p id="target">Текст</p>@layer base, theme;
@layer theme {
p { color: blue; }
}
@layer base {
#target { color: red; }
}<p>Текст</p>@layer base, theme;
@layer base {
p { color: red !important; }
}
@layer theme {
p { color: blue !important; }
}<p id="target">Текст</p>@layer base {
p { color: red !important; }
}
#target { color: blue; }<div class="outer">
<div class="inner">
<p>Текст</p>
</div>
</div>@scope (.inner) {
p { color: red; }
}
@scope (.outer) {
p { color: blue; }
}HTML
CSS
Какого цвета будет текст элемента <p>?
Для проверки ответов включите JavaScript. Пример: .note { color: red } сильнее записанного ниже p { color: blue } для <p class="note">: класс имеет вес 0–1–0, тег — 0–0–1.
Разобрать свой селектор
Введите селектор или выберите пример, чтобы увидеть его вес и вклад каждой части. Можно сравнить два селектора.
Вес A–B–C: идентификаторы — классы, атрибуты и псевдоклассы — типы и псевдоэлементы. Сравниваем слева направо, без переноса разрядов. Результат обновляется во время ввода.
Для расчёта включите JavaScript. Пример: #menu .item:hover имеет вес 1–2–0, а nav a.active — 0–1–2. Первый селектор специфичнее.