Возможно, вы сталкивались с ситуацией, когда вы задаете какое-то свойство для определенного селектора, но после этого ... ничего не происходит? В чем дело, не всегда можно понять, потому что, как правило, дело заключается в приоритете селекторов.

Приоритет, или вес селекторов - это понятие, которое определяет, как взаимодействуют одинаковые свойства, заданные  одному и тому же элементу в разных местах кода. Рассчитывается вес селекторов на основе такого пункта CSS-спецификации, как Calculating a selector's specificity. Согласно ему вес рассчитывается на основе выставления нулей и единиц в определенном разряде.

Давайте посмотрим на пример из спецификации:

То есть тут мы видим, что минимальный вес, равный нулю по всем 4-м позициям имеет универсальный селектор *, затем единица появляется  в селекторе тега li, для li.red.level уже наблюдаем двойку во втором справа разряде, для селектора id  в виде #x34y - единицу в третьем разряде и максимум - единицу в четвертом разряде мы увидим у стилей, встроенных в атрибут style="..." в самом элементе.

Если вам хочется быстро посчитать вес вашего селектора, стоит воспользоваться сервисом CSS Selector Specificity Calculator, на котором достаточно ввести нужный вам селектор. Обратите внимание на маркировку цветом разного веса для указанных селекторов.

Вес css-селекторов

Если же вы хотите чуть серьезней разобраться в системе, то дочитайте статью до конца.

Как складывается вес селекторов

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

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

  • Универсальный селектор: * - вес 0;
  • Элемент div,  псевдоэлемент ::before - вес 1;
  • Класс .menu, селектор атрибута [href^="#"],  псевдокласс :hover - вес 10:
  • Идентификатор #main - вес 100;
  • Использование встроенного атрибута style (инлайн-стиль) - вес 1000;
  • использование атрибута !important в свойстве - вес 10000.

Примечание: приведенные здесь примеры не описывают все варианты селекторов. Т.е. класс может быть .row или .item-link, в качестве псевдокласса можно указать :nth-child(2n), а атрибута -  [type="password"] и т.п.

Итак, если посчитать пример с картинки в виде строки #temp ul li a.menu > *, то мы имеем 100+1+1+1+10+0 = 113, т.е. именно те цифры, которые мы на картинке видим.

Аналогичный подход можно увидеть в CSS Specificity Graph Generator - при наведении на любую вершину графика вы увидите цифру аналогичного вида.

Есть также специфичные псевдоклассы типа :not(selector), :is(selector), :has(selector), которые "принимают вес" того селектора, который находится в скобках. Например, селектор .main > .item:not(.blue) содержит 3 класса, один из которых находится в псевдоклассе :not, поэтому получает вес 10*3 = 30. Очень похожий на него селектор, но содержащий в скобках тег, .main > .item:not(div) - уже получает вес 10*2+1 = 21.  А селектор .main > .item:is(#second), в котором в скобках уже появляется #id, считается, как 2*10+100 = 120.

Попробуйте сами в калькуляторе.

Обратите внимание еще на одну фишку - ставите вы пробел между селекторами или угловую скобку вправо >, никак не отображается на весе селекторов. Это, скорее важно для понимания того, на какую глубину вложенности данное css-правило(-а) будет распространяться.

Встроенный стиль и ключевое слово !important

Для того чтобы переопределить любые свойства для css-селекторов, можно использовать встроенный (инлайн) стиль, который записывается в любом теге, как атрибут style. Он имеет вес в 1000, поэтому легко переопределяет все, что вы задали даже для нескольких вложенных id.

Это, кстати, объясняет и тот факт, что многие плагины JavaScript добавляют к элементам свои встроенные стилевые свойства. С одной стороны, это просто реализовать с помощью свойства style в JavaScript, с другой - вы с довольно высокой вероятностью переопределите все, что было написано в css-стилях для этого элемента.

Однако и встроенным стилям есть противовес - это ключевое слово !important внутри описания свойства. Как правило, его нужно добавлять не всем css-свойствам подряд, а одному или двум. Он имеет приоритет 10000, соответственно, даже атрибут style здесь не помеха.

See the Pen Inline style & !important by Elen (@ambassador) on CodePen.

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

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

Неочевидный приоритет

Итак, у нас есть ситуация из 3-х цветовых классов и их комбинации в 4-м div-e:

Какой цвет фона будет у последнего div-a, если для всех классов описан соответствующий фон? Красный? Желтый? Синий?

See the Pen CSS 3 classes by Elen (@ambassador) on CodePen.

Уже посмотрели ответ? Правильно: красный, потому что в данном случае приоритет не сыграл, сыграло правило "кто позже появился, тот и работает". Т.е. в том случае, когда у нас есть одинаковые свойства в разных классах, но в таблице стилей один из классов описан ниже других, приоритет будет за ним. И не важно, что в 4-м div-e есть 3 класса с весом 30, а не 10, важно, что  css-свойство внутри всех одно и то же

Именно по этой причине в случае использования сторонних стилей, например, Bootstrap.css, вы подключаете свой style.css после чужого кода, т.к. в этом случае вы имеете возможность перезаписать стандартные стили своими собственными, используя те же селекторы, что и в стороннем css-файле.

Несколько слов о производительности

Используя сложные селекторы, вы, конечно, можете показать, насколько вы круты, как верстальщик. Но не стоит забывать, что разные селекторы обрабатываются браузером с разной скоростью. В далеком уже 2009 году Стив Саудерс проводил исследование и рассортировал CSS-селекторы по производительности — от наиболее быстрых до медленных:

  • Идентификатор: #id
  • Класс: .class
  • Элемент: div
  • Соседний элемент: h2 + p
  • Дочерний элемент: li > ul
  • Вложенный элемент: ul li
  • Общий селектор: *
  • Атрибут: [type="email"]
  • Псевдоклассы/псевдоэлементы: a:hover

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

Кроме того, если у вас есть необходимость, например, стилизовать ссылки в футере, вложенные в <li>, то, возможно, самым простым вариантом будет назначить этим ссылкам какой-либо класс:

Такой подход лучше тем, что каскад  уменьшился до минимума.

Сейчас очень многие фреймворки используют подход, основанный на мультиклассах: вы добавляете для одного элемента атрибут class="class-1 class-2 class-3", а уже в каждом классе есть одно или несколько разных свойств, которые сочетаются (складываются, плюсуются) при оформлении элемента на странице.

Ниже приведен небольшой фрагмент разметки на основе Tailwind CSS, взятый из примера оформления форм.

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

Проверка понимания приоритета селекторов

Уверены, что вы все поняли? Тогда пройдите 2 проверки от героев "Star Wars" автора Paulina Hetman на понимание приоритете селекторов. Ответьте на 17 вопросов, часть из которых повторяет рассмотренные примеры.

1. Определите вес селекторов - введите в каждое из полей типа "number" нужное число и проверьте результат. Обязательно посмотрите примеры на первом экране в самом низу.

See the Pen QUIZ: Can You Count Specificity? by Paulina Hetman (@pehaa) on CodePen.

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

See the Pen CSS Quiz - Specificity Wars by Paulina Hetman (@pehaa) on CodePen.

Автор: Админ

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

Ваш адрес email не будет опубликован. Обязательные поля помечены *