Специфика

Подкаст CSS - 003: Специфичность

Предположим, вы работаете со следующим HTML и CSS:

<button class="branding">Hello, Specificity!</button>
.branding {
  color: blue;
}

button {
  color: red;
}

Здесь два правила нацелены на один и тот же элемент. Каждое правило содержит объявление, которое задает цвет кнопки: одно пытается покрасить кнопку в красный цвет, а другое — в синий. Какое из этих объявлений будет применено к элементу?

Понимание алгоритма специфичности CSS — ключ к пониманию того, как CSS выбирает между конкурирующими объявлениями.

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

Оценка специфичности

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

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

Специфичность — это не десятичное число, а триада, состоящая из трех компонентов: A , B и C

  • A : специфичность, подобная id
  • B : специфичность, подобная классу
  • C : элементоподобная специфичность

Часто это обозначается с помощью обозначения (A,B,C) . Например: (1,0,2) . Также широко используется альтернативное обозначение ABC .

Диаграмма, иллюстрирующая три компонента специфичности (A, B, C). Для каждого компонента на диаграмме показано, что он представляет, и приведены примеры селекторов, влияющих на него.
Диаграмма, демонстрирующая, на какой компонент специфичности влияют различные селекторы.

Как сравнивать особенности

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

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

Селекторы влияют на специфичность

Каждая часть триады специфичности начинается со значения 0 , поэтому специфичность по умолчанию равна (0,0,0) . Каждая часть селектора увеличивает специфичность, которая, в зависимости от типа селектора, увеличивает значение либо A , B , либо C

Универсальный селектор

Универсальный селектор ( * ) не добавляет специфичности , оставляя свое значение равным исходной специфичности (0,0,0) .

* {
  color: red;
}

Селектор элемента или псевдоэлемента

Селектор элемента (типа) или псевдоэлемента добавляет специфичность, подобную специфичности элемента , увеличивая компонент C на 1 .

Приведенные ниже примеры имеют общую специфичность (0,0,1) .

Селектор типа

div {
  color: red;
}

Селектор псевдоэлементов

::selection {
  color: red;
}

Селектор класса, псевдокласса или атрибута

Селектор класса , псевдокласса или атрибута добавляет специфичность, подобную классу , увеличивая компонент B на 1 .

Следующие примеры имеют специфичность (0,1,0) .

Выбор класса

.my-class {
  color: red;
}

Селектор псевдоклассов

:hover {
  color: red;
}

селектор атрибутов

[href='#'] {
  color: red;
}

селектор идентификатора

Селектор ID добавляет специфичность, подобную идентификатору , увеличивая компонент A на 1, при условии, что вы используете селектор ID ( #myID ), а не селектор атрибута ( [id="myID"] ).

В следующем примере специфичность равна (1,0,0)

#myID {
  color: red;
}

Другие селекторы

В CSS много селекторов. Не все из них добавляют специфичность. Например, сам псевдокласс :not() ничего не добавляет к расчету специфичности.

Специфичность псевдокласса :not() заменяется специфичностью наиболее специфичного селектора в его аргументе селекторов, разделенном запятыми; обеспечивая ту же специфичность, как если бы он был написан :not(:is(argument)) .

div:not(.my-class) {
  color: red;
}

Псевдокласс :is() сам по себе не вносит вклад в расчет специфичности. Подобно :not() , он учитывает специфичность своего наиболее специфичного аргумента.

:is(h1, h2, h3) {
  color: blue;
}

Данный образец имеет специфичность (0,0,1) поскольку содержит только один тип селектора ( type ).

С добавлением id специфичность возрастает до (1,0,0) .

:is(h1, h2, h3, #my-heading) {
  color: blue;
}

Псевдокласс :where() отличается. Независимо от специфичности любого из его аргументов, он всегда имеет специфичность (0,0,0) .

:where(h1, h2, h3, #my-heading) {
  color: blue;
}

Стили с низкой специфичностью, применяемые с помощью :where() позволяют переопределить эти стили с помощью базовых селекторов позже в вашей таблице стилей:

:where(#my-content) {
   color: red;
}

p {
   color: blue;
}

Несмотря на то, что в списке аргументов функции :where() есть id , его специфичность по-прежнему ограничена (0, 0, 0) , поэтому базовый селектор p переопределяет его, и текст будет blue .

Проверьте свое понимание

Проверьте свои знания о методе оценки специфичности.

В чём заключается специфика a[href="#"] ?

(0,0,1)
Буква a » имеет значение (0,0,1) , а [href="#"] имеет значение (0,1,0) .
(0,1,0)
Попробуйте еще раз! Буква a » стоит (0,0,1) , а [href="#"] стоит (0,1,0) .
(0,1,1)
Значение a равно (0,0,1) , а значение [href="#"] равно (0,1,0) , что в сумме дает специфичность (0,1,1) .

Факторы, не влияющие на специфичность

Существуют некоторые распространенные заблуждения относительно следующих факторов, влияющих на специфичность.

Встроенные атрибуты стиля

Применение CSS-кода непосредственно к атрибуту style элемента не влияет на специфичность, поскольку это другой этап в каскаде , который выполняется перед определением специфичности.

<div style="color: red"></div>

Чтобы переопределить это объявление из таблицы стилей, необходимо добиться того, чтобы объявление имело приоритет на более раннем этапе каскада .

Например, вы можете добавить к нему !important , чтобы он стал частью исходного кода Authored !important .

!important заявления

Добавление !important в конце объявления CSS не влияет на специфичность, но перемещает объявление в другой источник , а именно в `Authored !important .

В следующем примере специфичность .my-class не имеет значения для того, чтобы объявление !important имело приоритет.

.my-class {
  color: red !important;
  color: white;
}

Когда два объявления имеют флаг !important , тогда снова вступает в игру специфичность, поскольку исходный этап каскада еще не смог определить победителя.

.branding {
  color: blue !important;
}

button {
  color: red !important;
}

Специфика в контексте

При использовании сложного или составного селектора каждая его часть в сумме определяет специфичность. Рассмотрим следующий HTML-код:

<a class="my-class another-class" href="#">A link</a>

Эта ссылка имеет два класса. Правило в следующем CSS имеет специфичность (0,0,1) :

a {
  color: red;
}

Если вы укажете один из классов в селекторе, он теперь будет иметь специфичность (0,1,1) :

a.my-class {
  color: green;
}

Добавьте другой класс к селектору, теперь он имеет специфичность (0,2,1) :

a.my-class.another-class {
  color: rebeccapurple;
}

Добавьте атрибут href к селектору, теперь он имеет специфичность (0,3,1) :

a.my-class.another-class[href] {
  color: goldenrod;
}

Наконец, добавив ко всему этому псевдокласс :hover , селектор в итоге получит специфичность (0,4,1) :

a.my-class.another-class[href]:hover {
  color: lightgrey;
}

Проверьте свое понимание

Проверьте свои знания о методе оценки специфичности.

Какой из следующих селекторов имеет специфичность (0,2,1) ?

article > section
Элементы добавляют специфичность, подобную специфичности элемента (компонент `C`). В селекторе 2 элемента, что делает его специфичным (0,0,2) .
article.card.dark
Элементы добавляют специфичность, подобную элементу (компонент `C`), а классы добавляют специфичность, подобную классу (компонент `B`). При наличии 2 классов и 1 элемента этот селектор имеет специфичность (0,2,1) .
article:hover a[href]
Элементы добавляют специфичность, подобную элементарной (компонент `C`), псевдоклассы и атрибуты добавляют специфичность, подобную классовой (компонент `B`). Имеется 2 селектора элементов (2 × (0,0,1) ), селектор атрибута (значение (0,1,0) ) и селектор класса (значение (0,1,0) ). Таким образом, общая специфичность этого селектора составляет (0,2,2) .

Прагматическое повышение специфичности

Допустим, у вас есть CSS-код, который выглядит примерно так:

.my-button {
  background: blue;
}

button[onclick] {
  background: grey;
}

В формате HTML это выглядит так:

<button class="my-button" onclick="alert('hello')">Click me</button>

Кнопка имеет серый фон, потому что второй селектор имеет специфичность (0,1,1) . Это связано с тем, что у него есть один селектор типа ( button ), который равен (0,0,1) и селектор атрибута ( [onclick] ), который равен (0,1,0) .

Предыдущее правило — .my-button — равно (0,1,0) потому что оно имеет один селектор класса, что обеспечивает более низкую специфичность, чем (0,1,1) .

Если вы хотите усилить это правило, вы можете повторить селектор класса следующим образом:

.my-button.my-button {
  background: blue;
}

button[onclick] {
  background: grey;
}

Теперь кнопка будет иметь синий фон, потому что новый селектор получает специфичность (0,2,0)

Связь в специфичности возвращает нас к следующему шагу в каскаде.

Продолжая пример с кнопкой, изменим CSS следующим образом:

.my-button {
  background: blue;
}

[onclick] {
  background: grey;
}

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

Если поменять местами правила в порядке следования исходных файлов, кнопка станет синей.

[onclick] {
  background: grey;
}

.my-button {
  background: blue;
}

Это происходит потому, что оба селектора имеют одинаковую специфичность. В этом случае каскад возвращается к порядку появления .

Ресурсы