Что такое специфичность в CSS

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

Типы селекторов CSS

Есть несколько способов выбрать элементы, которые вы хотите стилизовать в CSS. Давайте рассмотрим все доступные варианты.

  • Селекторы типа: выбирают нужный элемент, используя его тип. Например, чтобы выбрать все теги <p>, в таблице стилей CSS используется p.
  • Псевдоэлементы: как следует из названия, псевдоэлементы сами по себе не являются элементами, но позволяют выбирать часть HTML относительно другого селектора. Например, выбрать первую букву каждого абзаца можно с помощью p::first-letter.
  • Селекторы класса: элементам можно задать несколько классов, и эти классы можно выбирать таблице стилей CSS. Например, <h1 class=’header’> можно выбрать с помощью .header. Один и тот же класс можно применить одновременно к нескольким элементам.
  • Селекторы атрибута: выбирают элементы, к которым применен определенный тип атрибута. Например, чтобы выбрать входящие данные, которые принимают только числа, можно с input[type=’number’].
  • Псевдоклассы: выбирают элементы на основе состояния CSS, в котором они находятся. К примеру, стилизовать состояние наведения кнопки можно с помощью псевдокласса button:hover.
  • Селекторы ID: выбирают определенный элемент по его уникальному идентификатору. Каждый идентификатор может принадлежать только одному конкретному элементу (в отличие от классов, которые могут применяться к нескольким элементам одновременно). Например, чтобы выбрать <h1 id=’mainHeader’>, можно использовать селектор #mainHeader.
  • Встроенные стили: применяются к элементам непосредственно с помощью атрибута style, поэтому фактически вы не используете никакие селекторы CSS при работе с ними. Например, вы можете сделать цвет шрифта заголовка синим просто с помощью <h1 style=’color: blue;’>

Читайте также: Создание псевдоклассов в CSS

Селекторы CSS и их вес

Все перечисленные выше селекторы имеют вес. По этому критерию их можно разделить на четыре основные группы:

  • наименьший вес: селекторы типа и псевдоэлементы
  • малый вес: селекторы класса, атрибута и псевдоклассы
  • средний вес: селекторы ID
  • большой вес: встроенные стили

Если к одному и тому же элементу применяются стили с разным весом, в результате CSS отобразит стиль с наибольшим весом. В случае, если к одному элементу применяются несколько стилей с одинаковым весом, в итоге CSS отобразит тот стиль, который идет последним (то есть находится ближе к концу таблицы стилей). Это связано с «каскадным» эффектом CSS (Cascading Style Sheets).

Примечание: К любому стилизованному элементу будет применен последний блок стиля с наибольшим весом. Однако встроенные стили всегда превзойдут стили селекторов CSS.

Когда к одному элементу применяются два селектора одинакового веса, вес удваивается. Так, например, элемент с двумя классами будет иметь более высокий вес, чем элемент с одним классом.

.gator.cayman { // два класса
  color: purple;
}

.gator { // один класс
  color: purple;
}

Основная проблема, с которой в какой-то момент сталкивается большинство веб-разработчиков, — наличие нескольких стилей, которые конфликтуют друг с другом. Если вы используете фреймворк CSS, например Material UI, возможно, вы можете попробовать переопределить некоторые стили по умолчанию. Также это часто происходит в старых (и плохо организованных) файлах styles.css, где постоянно приходится повышать специфичность, потому что уже неясно, почему стили не применяются должным образом.

Имея хорошее представление об инструментах, вы сможете лучше и эффективнее их использовать. Далее мы взглянем, как различные комбинации селекторов влияют на специфичность, и изучим некоторые хитрости, чтобы ваши стили применялись по назначению.

Конкурирующие селекторы

Понимание того, что разные селекторы имеют разный вес, имеет решающее значение для организации вашего CSS-файла. Но что делать, если непонятно, какой из селекторов имеет больший вес?

Допустим, у нас есть абзац с двумя конкурирующими блоками CSS: один с тремя одинаковыми по весу классами, а второй с атрибутом типа и двумя одинаковыми классами.

Возьмем этот ввод с тремя классами и примененным к нему атрибутом number.

<input type='number' class='gator cayman reptile'>

Если мы применим эти конкурирующие селекторы (три одинаковых класса против двух одинаковых классов и атрибута), какой из них будет применен в итоге?

.gator.cayman.reptile {
  color: purple;
}

[type='number'].gator.cayman {
  color: green;
}

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

Однако все становится немного сложнее, когда встречаются селекторы разного веса.

Предположим, у нас есть ID, который, как мы уже знаем, имеет больший вес, чем классы и атрибуты.

<input
  type='number'
  id='gatorInput'
  class='gator cayman reptile'>

Итак, у нас снова есть конкурирующие стили, где использован идентификатор для одного и классы/атрибуты для другого. Так что в итоге будет применено?

#gatorInput {
  color: purple;
}

[type='number'].gator.cayman.reptile {
  color: green;
}

В первом блоке стиля используется только один идентификатор. Во втором блоке – три класса и селектор атрибутов, и он идет последним. Несмотря на то, что во втором блоке больше селекторов, селектор ID имеет больший вес, и текст будет фиолетовым!

Примечание: Селекторы с более высоким весом всегда будут превосходить селекторы с меньшим весом, даже если селекторов с меньшим весом несколько.

Хак с весом селектора

Если вашему селектору CSS нужно немного больше веса, — просто повторите класс в том же блоке.

input.gator.gator {
  color: purple;
}

input.gator {
  color: green;
}

Вас может удивить тот факт, что первый блок имеет вес двух классов, а второй – одного класса, хотя по сути в первом просто дважды повторяется класс .gator. Однако два класса имеют более высокий вес, чем один, и вводимый текст будет фиолетовым!

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

Специфичность в CSS: подробный пример

Иногда механизм специфичности может показаться нелогичным, особенно если вы ходите по кругу, постоянно добавляя все больше и больше селекторов в свой CSS. Один из способов, который может прояснить работу специфичности — это сравнение специфичности с компанией, в которой есть четкие уровни старшинства.

Роли в компании в порядке старшинства (от низшей к высшей) таковы:

  • сотрудники
  • менеджеры
  • директора
  • вице-президенты
  • один генеральный директор (мы вернемся к нему чуть позже)

Давайте теперь сопоставим эти роли с нашими селекторами:

  • сотрудники: селекторы типа и псевдоэлементыв
  • менеджеры: селекторы класса, атрибута и псевдоклассы
  • директора: селекторы идентификатора
  • вице-президенты: встроенные стили

Теперь посмотрите на новый пример кода. В этом случае у нас есть абзац с двумя классами и идентификатором.

<p id='gatorParagraph' class='gator reptile'>
  blah blah blah
</p>

#gatorParagraph {
  color: purple;
}

p.gator.reptile {
  color: green;
}

У нас есть один блок, в котором используется только ID, и второй блок, в котором используется тип элемента (<p>) и два класса. На первый взгляд может быть трудно понять, какой из них имеет больший вес.

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

Примечание: Конечно, решения в компании едва ли должны приниматься таким методом.

Если селекторы на том же уровне не могут решить, какой стиль применять, при эскалации решение будет передано селектору более высокого уровня.

Примечание: Как правило, лучше всего писать достаточно конкретный CSS, чтобы вам не приходилось искать способы его эскалации. Имейте в виду, что как только вы введете новый уровень старшинства (например, добавите идентификатор), вы можете случайно переопределить другие стили.

Правило !important

Мы уже провели аналогию между селекторами и должностями компании. Однако до сих пор мы не выяснили, кто является генеральным директором нашей компании в контексте CSS. Разве есть что-то выше встроенного стиля? Да, это правило !important.

Используем тот же пример, что и раньше, и добавим !important в блок, который ранее имел меньший вес.

#gatorParagraph {
  color: purple;
}

p.gator.reptile {
  color: green !important;
}

Правило !important всегда повышает старшинство до максимально возможного уровня. По сути у нас теперь есть директор против сотрудника, двух менеджеров и генерального директора. Как только в блоке появляется генеральный директор, этот блок превосходит все остальные.

Недостатки правила !important

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

Кроме того, !important часто чрезмерно используется в стилях, как показано в примере ниже. Правила !important рано или поздно уравновешивают друг друга, а значит, вы снова должны понимать вес и продумывать каскадность каждого блока.

#gatorParagraph {
  color: purple !important;
}

p.gator.reptile {
  color: green !important;
}

Прежде чем ввести правило !important, попробуйте открыть инструменты разработки в браузере и разобраться, какие стили конфликтуют.

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

Примечание: Правило !important очень часто становится причиной появления конкурирующих стилей CSS – именно потому, что !important используется в нескольких блоках.

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

Универсальный селектор (*) и комбинаторы не влияют на вес селекторов. К комбинаторам относятся дочерние селекторы (>), общие одноуровневые селекторы (~) и соседние одноуровневые селекторы (+).

Например, у нас есть абзац с двумя интервалами. Дочерний комбинатор не повысит специфичность:

<p id='gatorParagraph'>
  <span class='reptile'>eggs</span>
  <span class='reptile'>nest</span>
</p>


#gatorParagraph > .reptile {
  color: purple;
}

#gatorParagraph .reptile{
  color: green;
}

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

Заключение

Одно из лучших наглядных пособий по специфичности CSS называется specifishity.

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

Читайте также:

Tags:

Добавить комментарий