Специфика селектора является реальной проблемой для большинства средних и крупных проектов, и, как и любая другая часто повторяющаяся проблема кодирования, ее необходимо тщательно решать. Даже у CSS-Tricks недавно была статья о том, как сохранить низкую специфичность CSS .
И прежде чем вы даже попытаетесь сказать !important
напомнить, что:
Специфика CSS не так уж сложна, но сообщество сделало многое для того, чтобы сделать его как можно более легким для понимания, написания руководств, используя аналогии с рыбой и « Звездными войнами» , или используя покерную терминологию . В Интернете доступны интерактивные калькуляторы и даже набор специфичности для Sass , позволяющий проверить и вывести точное значение специфичности селектора.
Проще проще, когда речь идет о стратегии специфичности CSS, обходные пути специфичности в этой статье (которые могут показаться немного странными) подходят для случаев, когда архитектура не допускает простого исправления. Примите решение, какой подход лучше всего подходит для вашего проекта, и в конечном итоге постарайтесь найти идеальный баланс между чистым и поддерживаемым CSS.
Подход № 0 — БЭМ
BEM — это больше, чем просто соглашение об именах, это интерфейсный инструмент, изобретенный Яндексом, философия которого заключается в том, чтобы приблизиться к объектно-ориентированному программированию. На практике это означает использование имени класса для каждой вещи, которую вы стилизуете. Хотя для некоторых «каскадирование в каскадных таблицах стилей» может показаться нелепым, идея никогда не использовать селекторы типа и избегать вложения очень полезна при создании модулей, которые должны быть обслуживаемыми, переносимыми, самодостаточными, легко модифицируемыми и масштабируемый.
Одно из главных преимуществ методологии БЭМ заключается в том, что она сохраняет специфичность для каждого селектора, поэтому должно быть практически нулевое количество проблем, вызванных чрезмерно конкретными селекторами, поэтому этот подход № 0 — если вы его принимаете, вы по сути устранение любых будущих проблем со спецификой селектора в проекте.
Специфика Правил
Поскольку вы будете использовать только один класс для всего, что вы пишете, каждый отдельный селектор будет иметь специфичность 0,1,0
Когда БЭМ не ответ
Существует бесчисленное множество историй успеха передовых архитектур, использующих BEM, однако, как бы ни была популярна BEM, она не подходит для конкретного типа проектов. Кажется, он отлично работает для проектов, где разработчики интерфейса — единственные люди, которые пишут HTML. Однако если вы пишете для CMS, где редакторы контента без каких-либо навыков HTML пишут хотя бы часть контента, то BEM будет строго ограничивать.
БЭМ в чистом виде не допускает вложенности и селекторов типа, таких как .Section--dark > a
(например, для выделения светлого цвета), вместо этого он требует, чтобы вы изобрели класс для тега привязки. Это приводит к проблеме — редактор содержимого вставит ссылку по умолчанию через графический интерфейс, что может привести к появлению плохо видимых ссылок. Это также может относиться ко всем абзацам, спискам или изображениям в определенном разделе. Иногда требуется возможность писать чистый HTML-контент без классов, в таких случаях решение заключается в том, чтобы все это стилировалось самим родителем с потомками-селекторами. Такое использование каскадирования обеспечивает контекстную гибкость — наличие пользовательских стилей для чего-либо, когда это происходит в другом контексте.
Поэтому нам нужно реальное решение, когда мы не можем использовать чистый БЭМ, что довольно часто. Здесь нам могут помочь препроцессоры CSS, и все 3 популярных из них — LESS, Sass и Stylus — могут облегчить нашу работу, когда нам нужно переопределить селектор более конкретным.
Подход № 1 — подготовить с помощью селектора
Когда вы сталкиваетесь с проблемой специфичности и хотите сделать определенный селектор более тяжелым, вы можете добавить существующий селектор к классу, атрибуту, идентификатору или селектору типа. Таким образом, вы можете немного увеличить специфичность. Хотя эта функция в основном используется для таргетирования IE с помощью условного тега html , она обладает гораздо большими возможностями, которые еще предстоит использовать.
Селектор родительской ссылки ( &
) в препроцессорах CSS легко позволяет нам добавить селектор, чтобы сделать его более тяжелым, поэтому мы можем сделать следующее:
.class { body & { foo: bar; } }
В результате этого CSS
body .class { foo: bar; }
Возможно, вы захотите добавить его к тегу html
или body
, но вы также можете использовать что-то более конкретное, присутствующее на всех ваших страницах, например #wrapper
, #wrapper
, html[lang]
и т. Д.
Sass позволяет вам поместить предваряющий селектор в переменную в случае будущих изменений, кроме того, для более крупных проектов может быть целесообразно создать набор предваряющих селекторов с различными весами:
$prepend1: "html &"; $prepend2: "#wrapper &"; .selector { #{$prepend1} { background: #cacaca; } #{$prepend2} { background: #fefefe; } }
Что приведет к:
html .selector { background: #cacaca; } #wrapper .selector { background: #fefefe; }
Другие популярные препроцессоры, такие как LESS и Stylus, также предлагают эту функциональность.
Специфика Правил
Если мы 0,1,0
исходный селектор класса 0,1,0
с помощью селектора типа, получится 0,1,1
, а с идентификатором — 1,1,0
.
Недостаток в том, что когда вы добавляете что-то к #wrapper
тяжелому селектору (например, #wrapper
), вы больше не можете его переопределять, пока не изобретете новый, более тяжелый селектор, что не всегда возможно.
Подход № 2 — Самосцепные селекторы
Предварительный выбор селектора полезен, но это не бесконечно масштабируемое решение — у вас может быть ограниченное количество способов нацелить на родителя. Кроме того, как только вы добавляете более одного селектора к самому тяжелому параметру в своем коде, вы ограничиваете свои варианты для решения проблемы специфичности позже (особенно если вы использовали идентификатор).
Сообществу переднего плана недавно напомнили об одной очень полезной функции CSS — самостоятельной цепочке селектора для повышения его специфичности . Самосцепные селекторы работают с идентификаторами, классами, селекторами атрибутов, но не с селекторами типов. Тем не менее, если вы используете преимущественно классы для стилизации своего контента, самостоятельная цепочка предлагает вам бесконечно масштабируемый способ переопределить любой селектор.
С помощью родительского ссылочного селектора вы можете легко связать один и тот же селектор с собой несколько раз (это относится к идентификаторам, классам и селекторам атрибутов, но не к селекторам типов). Вам нужно будет интерполировать каждый &
после первого, хотя минимальное требование — Sass 3.4:
.selector { &#{&} { background: #cacaca; } &#{&}#{&} { background: #fefefe; } }
.selector.selector { background: #cacaca; } .selector.selector.selector { background: #fefefe; }
Еще раз, вы также можете сделать это с LESS и Stylus .
Если это слишком уродливо для вашего вкуса, вы всегда можете создать миксин, который может многократно увеличить специфичность любого отдельного селектора. Этот миксин использует некоторые расширенные функции, а также требует Sass 3.4:
@mixin specificity($num: 1) { $selector: &; @if $num > 1 { @for $i from 1 to $num { $selector: $selector + &; } @at-root #{$selector} { @content; } } @else { @content; } } .selector { @include specificity(2) { background: #cacaca; } @include specificity(3) { background: #fefefe; } }
В результате получается следующий CSS:
.selector.selector { background: #cacaca; } .selector.selector.selector { background: #fefefe; }
Вы можете создать идентичный миксин в Stylus , к сожалению, в LESS нет простых способов создать такой миксин.
Специфика Правил
Самосцепление увеличит специфичность селектора с 0,1,0
до 0,2,0
до 0,3,0
и т. Д., Что делает его практически бесконечно масштабируемым.
Последние мысли
Следующим естественным шагом в решении проблем специфичности в нашем более умном, чем когда-либо, CSS было бы создание способа выявления конфликтующих объявлений, вычисления специфичности каждой из сущностей с помощью чего-то вроде микса Sass Дэвида Хуршида и последующего автоматического использования одного из подходов. выше, чтобы увеличить специфичность. Может быть, мои мечты о самосознающих таблицах стилей слишком оптимистичны, но я думаю, что по мере развития препроцессоров CSS сложная логика в нашем коде будет увеличиваться.
Какой из вышеперечисленных методов вы бы использовали в следующий раз, когда вам нужно будет бороться со специфическими проблемами? Какие еще стратегии вы используете для решения своих проблем?