Заблуждения о Специфичности CSS

Источник: «Misconceptions about CSS Specificity»
Всякий раз, когда публикуется статья о Специфичности в CSS — и, как следствие, о самом Каскаде — я очень радуюсь, ведь это основная концепция языка, которую должен знать каждый. Чем больше статей об этом, тем лучше!

Однако иногда я также поднимаю бровь, поскольку иногда, к сожалению, сталкиваюсь с тем, что просто откровенно неправильно.

Чтобы устранить путаницу, вот список заблуждений о Специфичности в CSS…

Заблуждение 1: Специфичность — это десятичная оценка

В некоторых, обычно старых, статьях Специфичность выражается в десятичной оценке или упоминается, что такая вещь, как селектор классов, добавляет 10 очков. Это неточно, поскольку подразумевается, что 11 селекторов элементов с их 1 баллом за каждый победят 1 селектор класса, который имеет только 10 баллов.

Вместо этого Специфичность — это триплет (или триада), состоящий из трёх компонентов: A, B и C. Значения A, B и C зависят от того, какой тип селектора вы используете.

Её часто представляют с помощью нотации (A,B,C). Например: (1,0,2). Также часто используется альтернативная нотация A-B-C.

🤓 Я написал библиотеку JavaScript, которая может вычислять специфичность селектора: @bramus/specificity. Она используется в этом интерактивном калькуляторе специфичности.

Специфичность сравнивается путём сопоставления трёх компонентов по порядку: специфичность с большим значением A является более специфичной; если два значения A равны, то специфичность с большим значением B является более специфичной; если два значения B также равны, то специфичность с большим значением C является более специфичной; если все значения равны, то две специфичности равны.

В коде это выглядит так:

const compare = (s1, s2) => {
if (s1.a === s2.a) {
if (s1.b === s2.b) {
return s1.c - s2.c;
}
return s1.b - s2.b;
}
return s1.a - s2.a;
};

Например, (1,0,0) обладает более высокой специфичностью, чем (0,10,3), поскольку значение A в (1,0,0) (равное 1) больше, чем значение A из (0,10,3) (равное 0).

Также посмотрите этот отрывок из моего выступления на CSS Day 2022 о каскаде:

Отрывок из моего выступления на CSS Day, посвящённого каскаду и рассказывающего о том, как писать и сравнивать специфичность

💡 Хотя вы можете представить триаду в виде десятеричного числа, добавив достаточное количество ведущих нулей, это сопряжено с определёнными трудностями: число, которое вы получите в итоге, трудно читать/разбирать + вам нужно будет добавить «достаточно» нулей, чтобы получить корректно сортируемый результат.

Мой совет: не надо.

Откуда взялась путаница

Ещё в CSS Selectors 3, в спецификации упоминалось, что можно объединять числа, для получения специфичности.

Конкатенация трёх чисел a-b-c (в системе счисления с большим основанием) даёт специфичность.

*               /* a=0 b=0 c=0 -> специфичность =   0 */
LI /* a=0 b=0 c=1 -> специфичность = 1 */
UL LI /* a=0 b=0 c=2 -> специфичность = 2 */
UL OL+LI /* a=0 b=0 c=3 -> специфичность = 3 */
H1 + *[REL=up] /* a=0 b=1 c=1 -> специфичность = 11 */
UL OL LI.red /* a=0 b=1 c=3 -> специфичность = 13 */
LI.red.level /* a=0 b=2 c=1 -> специфичность = 21 */
#x34y /* a=1 b=0 c=0 -> специфичность = 100 */
#s12:not(FOO) /* a=1 b=0 c=1 -> специфичность = 101 */

Хотя оговорка в системе счисления с большим основанием была проигнорирована, скорее всего, потому, что в спецификации были приведены примеры с основанием 10 — например, #s12:not(FOO) /* a=1 b=0 c=1 -> specificity = 101 */.

Прошло почти 15 лет, а мы до сих пор не можем с этим справиться: некоторые авторы продолжают представлять Специфичность в базе 10, потому что это проще для объяснения. Возможно, это и так, но это учит людей неправильным вещам. Впоследствии заставить их переучиваться гораздо сложнее.

Заблуждение 2: Использование атрибута style добавляет Специфичности

Я часто читаю, что использование атрибута style добавляет 1000 пунктов специфичности. Это неверно, поскольку оценка атрибута style является более ранним шагом каскада — она вообще не имеет отношения к специфичности.

Различные ступени каскада (согласно CSS Cascade 5), с выделенным атрибутом стиля
Различные ступени каскада (согласно CSS Cascade 5), с выделенным атрибутом стиля

Откуда взялась путаница

Во времена CSS2 (в 2011 году) это было действительно так. В той спецификации Специфичность была четверной (A, B, C, D), атрибут style был компонентом A.

Однако с появлением CSS3 это уже не так.

Заблуждение 3: Использование !important добавляет Специфичности

Я часто читаю, что добавление !important к декларации «добавляет 10000 пунктов специфичности». Это неверно, так как использование !important помещает декларацию в другой источник. При использовании !important в авторских стилях декларация переходит из источника Normal Author Declarations в источник Important Author Declarations.

Различные источники (согласно CSS Cascade 5) с обычными авторскими декларациями и выделенными важными авторскими декларациями
Различные источники (согласно CSS Cascade 5) с обычными авторскими декларациями и выделенными важными авторскими декларациями

Источники и важность — это первый критерий каскада, который проверяется. Специфичность появляется гораздо позже.

Откуда взялась путаница

Я не смог найти никаких следов в спецификациях, но предполагаю, что кто-то придумал это в те времена, когда критерий Специфичность напрямую следовал за критерием Источники/Origins. Тогда такое упрощение имело смысл, но сейчас оно уже не имеет смысла, поскольку пропускает три дополнительных критерия каскада, которые находятся между Источниками+Важность и Специфичностью: Контекст, Стили прикреплённые к элементу, и Слои.

Узнать больше

Чтобы узнать больше о Специфичности и Каскаде, рекомендую посмотреть доклад, который я делал на CSS Day 2022 и в нем рассказывается обо всем, что нужно знать об этом.

В статье The CSS Cascade: A Deep Dive (2022.06.09 @ CSS Day) на сайте https://www.bram.us/ также можно посмотреть слайды.

Дополнительные материалы

Предыдущая Статья

Некоторые интересные вещи из SQLite

Следующая Статья

Atomic CSS: Масштабируемая архитектура в современной веб-разработке