Вы сверстали страницу, пишете стили и вдруг понимаете — что-то не так. Текст, который должен быть зелёным, почему-то остался красным:
<p class="text">Это просто текст</p>
.text {
color: red;
}
p {
color: green;
}
Вы столкнулись со специфичностью селекторов: свойства не переопределились, потому что у .text
больший вес. Давайте разбираться, что здесь происходит.
Что такое специфичность селекторов
Разработчики часто применяют к одному элементу сразу несколько CSS-правил. Если два свойства из разных правил конфликтуют, браузер смотрит на селекторы. Свойство из CSS-правила с более «сильным» селектором побеждает в конфликте.
💡 Специфичность определяет приоритет CSS-правил у разных селекторов.
Как распределяется специфичность:
- Наибольшая специфичность у встроенных стилей.
- Меньше — у селекторов идентификаторов.
- Ещё меньше — у классов, псевдоклассов и селекторов атрибутов.
- Самый низкий приоритет у селекторов типов элемента и псевдоэлементов.
«Перебить» специфичность встроенных стилей можно только одним способом — использовать модификатор !important
. Но это плохая практика: такие стили почти невозможно переопределить. Разве что использовать более специфичный селектор и указать CSS-правило с ещё одним !important
.
Как посчитать специфичность селекторов
Порой в коде встречаются сложные конструкции. Например, стили для элемента <li>
в меню:
ul .list-item.list-active {
color: blue;
}
ul #catalog.list-item {
color: yellow;
}
Чтобы определить, какое из правил применится, надо посчитать вес селекторов. Чем больше вес, тем выше специфичность.
Вес записывается в виде a, b, c, d, где:
- a — встроенные стили,
- b — селектор по идентификатору,
- c — селектор классов псевдоклассов и атрибутов,
- d — селектор по тегу и псевдоэлементу.
Если в цепочке есть один из этих селекторов, то на его место в строке a, b, c, d ставится единица. Если нет — нуль.
Посчитаем на примере ul .list-item.list-active
:
- Встроенных стилей нет. Ставим нуль — 0, b, c, d.
- Идентификатора тоже нет, добавляем на его место нуль — 0, 0, c, d.
- Есть два класса, каждый весит единицу. Складываем их и подставляем в формулу: 0, 0, 2, d.
- Тег один, ставим 1.
Получается, вес ul .list-item.list-active
— 0, 0, 2, 1.
Теперь можно рассчитать вес ul #catalog.list-item
. Здесь тоже нет встроенных стилей, но есть один идентификатор, класс и тег. Получаем 0, 1, 1, 1.
Сравниваем вес селекторов — у второго он больше, поэтому пункт меню станет жёлтым.
💡 Сложно запомнить? Считайте специфичность в онлайн-калькуляторе.
Специфичностью можно управлять. Например, если вы хотите придать веса селектору, навесьте на него дополнительный тег или класс: .news
→.news.main-news
. Только не используйте длинные цепочки. Идеально, когда вложенность селекторов не больше трёх — такой код проще читать и поддерживать. Если же селекторов больше — возможно, стили стоит переписать.
Нюансы
Селекторы с использованием +
и ~
, а также псевдокласс :where()
не увеличивают уровень вложенности.
Специфичность не зависит от последовательности селекторов. У .list-item#catalog
и #catalog.list-item
одинаковый вес.
Псевдокласс :not
не учитывают при подсчёте специфичности — считают только расположенные в нём селекторы.
Немного практики
Вес селектора — 0, 1, 2, 0.
Вес #popup-button
— 0, 1, 0, 0
Вес .popup-button.popup.link.button.green-button.big-button.decorate-button.shadow-button.square-button.border-button:hover
— 0, 0, 11, 0.
Первый селектор специфичнее. Хотя у второго селектора 10 классов (никогда не делайте так) и псевдоэлемент, его вес ниже.
<button style="background-color: blue" type="button">Это кнопка</button>
button {
background-color: black !important;
}
Кнопка будет чёрной. Модификатор !important
даёт наивысший приоритет.
Материалы по теме
- Как работает каскад в CSS
- Что такое выражения от стилей
- Свойство display в CSS
- Простая анимация на чистом CSS