Открыть сервис

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

Специфичность селектора (англ. selector specificity) — это мера, определяющая, какие именно CSS-правила будут применены к элементу веб-страницы в случае, когда несколько правил конфликтуют между собой. Специфичность является одним из ключевых механизмов каскадирования в CSS (Cascading Style Sheets) наряду с порядком объявлений и использованием ключевого слова !important. Она вычисляется на основе типов и количества селекторов, входящих в состав CSS-правила.

Принцип работы

Специфичность не является абсолютным значением, а представляет собой систему приоритетов, основанную на весовых категориях. Каждое CSS-правило получает «вес», который складывается из весов его селекторов. Браузер, обнаружив, что к одному элементу применяются несколько правил с одинаковыми свойствами, выбирает то, у которого специфичность выше. Если специфичность правил одинакова, применяется правило, объявленное позже в исходном коде (принцип порядка).

Система весов

Специфичность обычно представляется в виде четырёхзначного числа (например, 0,0,1,0) или, в более современных интерпретациях, как кортеж из трёх или четырёх уровней. Наиболее распространённая модель, описанная в спецификации CSS W3C, включает четыре уровня:

  1. Стили в атрибуте style (inline-стили): имеют наивысший приоритет. Их специфичность считается равной 1,0,0,0.
  2. Селекторы по идентификатору (ID): каждый #id добавляет 0,1,0,0.
  3. Селекторы классов, атрибутов и псевдоклассов: каждый .class, [attr], :hover, :nth-child() добавляет 0,0,1,0.
  4. Селекторы элементов (тегов) и псевдоэлементов: каждый div, p, ::before, ::after добавляет 0,0,0,1.

Универсальный селектор (*), комбинаторы (+, >, ~, ) и псевдокласс :where() (в спецификации CSS) не добавляют веса. Псевдокласс :not() и :is() принимают вес самого специфичного аргумента внутри себя, а не самого псевдокласса.

Примеры вычисления

СелекторСпецифичность (ID, Class, Element)Пояснение
p0,0,0,1Один элемент
.text0,0,1,0Один класс
#main0,1,0,0Один идентификатор
div p0,0,0,2Два элемента
.menu li.active0,0,2,1Два класса и один элемент
#header .nav a0,1,1,1Один ID, один класс, один элемент
style="color: red;"1,0,0,0Inline-стиль

Влияние !important

Объявление свойства с ключевым словом !important (например, color: red !important;) полностью нарушает обычную систему специфичности. Такое объявление получает наивысший приоритет, переопределяя любые inline-стили и селекторы с любой специфичностью. Исключением является только другое объявление с !important, имеющее более высокую специфичность селектора, или объявление с !important в анимации (@keyframes). Использование !important считается плохой практикой, так как усложняет отладку и поддержку стилей.

Специфичность и каскад

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

  1. Происхождение стилей: стили автора (веб-разработчика) имеют приоритет над стилями пользователя (настройки браузера пользователя), которые, в свою очередь, имеют приоритет над стилями браузера по умолчанию (user-agent stylesheet).
  2. Специфичность: среди правил одного происхождения выбирается правило с наибольшей специфичностью.
  3. Порядок: если специфичность правил равна, применяется то, которое объявлено позже в коде (или в последнем подключённом файле).

Критика и сложности

Система специфичности часто подвергается критике за неинтуитивность и сложность в крупных проектах. Основные проблемы:

  • Гонка вооружений: разработчики начинают использовать всё более длинные и специфичные селекторы (например, #content .wrapper .sidebar .widget p), чтобы переопределить предыдущие стили, что ведёт к «раздуванию» кода.
  • Сложность отладки: определить, почему конкретное свойство не применяется, может быть трудно без инструментов разработчика браузера.
  • Конфликт с БЭМ и другими методологиями: методологии именования классов (например, БЭМ) стремятся к тому, чтобы все селекторы имели одинаковую специфичность (один класс), что делает систему более предсказуемой, но требует строгой дисциплины.

Современные подходы

Для борьбы с проблемами специфичности в CSS были введены новые возможности:

  • :where() — псевдокласс, который принимает список селекторов, но его собственная специфичность всегда равна нулю. Это позволяет легко переопределять стили, не увеличивая вес селектора.
  • :is() — псевдокласс, который принимает список селекторов, но его специфичность равна специфичности самого специфичного аргумента в списке.
  • CSS Layers (@layer) — механизм, позволяющий явно управлять порядком применения стилей, независимо от специфичности. Разработчик может определить слои (например, «сброс», «компоненты», «утилиты») и задать их приоритет, что делает систему более модульной.

Интересные факты

  • Специфичность селектора не является десятичным числом. Например, селектор с 11 классами (0,0,11,0) не переопределит селектор с одним идентификатором (0,1,0,0), так как каждый разряд работает независимо. Однако в старых браузерах (например, Internet Explorer 6) существовала ошибка, связанная с переполнением разряда.
  • Псевдоэлементы (::before, ::after) в спецификации CSS 2.1 имели специфичность 0,0,0,1, что приравнивало их к обычным элементам.
  • Специфичность селектора #id в 100 раз выше, чем селектора класса, если рассматривать её как четырёхзначное число, но в реальности это не арифметическое, а позиционное сравнение.

Источники

  1. Спецификация CSS Cascading and Inheritance Level 4 (W3C).
  2. Документация MDN Web Docs: «Специфичность».
  3. Книга «CSS: The Definitive Guide» (Эрик Мейер, Эстель Уэйл).
  4. Статья «Specifics on CSS Specificity» (CSS-Tricks).

BFOmetr — база данных и аналитика по компаниям России.

На главную BFOmetr →