Группировка селекторов
Для того, чтобы уменьшить количество кода после компиляции, а также упростить работу с селекторами, в Less был введён специальный псевдокласс :extend()
. Этот псевдокласс позволяет производить группировку селекторов (объединение) за счёт перечисления нескольких классов в одном месте, при условии, что все эти селекторы имеют общие свойства. Проще говоря, псевдокласс :extend()
автоматизирует следующий процесс:
- Найти селекторы, у которых есть одинаковые свойства.
- Выбрать базовый селектор.
- Перечислить все найденные селекторы в объявлении базового селектора.
- Все новые селекторы добавлять в список селекторов базового объявления.
Под списком селекторов понимается последовательность селекторов, разделяемая с помощью запятой. Я более чем уверен, что вы уже встречали такие списки и даже их использовали в своих проектах.
Следующих код демонстрирует такой список:
.header,
.main,
.footer {
background-color: #f5f5f5;
}
Раньше такие мероприятия производились вручную, и то при желании разработчика. Поверьте, это очень ресурсоёмкое занятие и самое ужасное — это когда элемент на странице меняет своё оформление. В этом случае приходится пользоваться поиском и повторять определённую последовательность действий каждый раз, когда встречается искомый селектор. Выполняются такие мероприятия лениво, неохотно и без особого энтузиазма. К счастью, разработчики препроцессора Less нашли способ борьбы с этим недугом.
Окей, а что же тогда предлагают препроцессоры? — писать код и не обращать внимание на такие мелочи. Конечно, такое говорится с оговоркой на то, что изредка придётся использовать препроцессорный псевдокласс :extend()
.
Рассмотрим несколько тривиальных примеров для погружения в курс дела и получения первого опыта работы с :extend()
.
Пример 2.4.1
Чтобы понять, как работает этот псевдокласс, представим, что у нас есть три селектора и свойства у них одинаковые.
.class-1 {
background-color: #fff;
color: #000;
}
.class-2 {
background-color: #fff;
color: #000;
}
.class-3 {
background-color: #fff;
color: #000;
}
В этом случае можно полностью объединить .class-1
, .class-2
и .class-3
. Если провести такие манипуляции с нашим примером, то получится следующий код:
.class-1,
.class-2,
.class-3 {
background-color: #fff;
color: #000;
}
Less предлагает эквивалентное решение, но в тоже время более простое. Он говорит нам, что нужно объявить полностью лишь селектор .class-1
, а другие сгруппировать с ним. Для этого предлагается использовать :extend()
.
.class-1 {
background-color: #fff;
color: #000;
}
.class-2:extend(.class-1) {}
.class-3 {
&:extend(.class-1);
}
Важно понимать, что использовать :extend()
можно как и любой другой псевдокласс. Имеется в виду, что допустимо как прямое написание (.class:extend()
), так и с использованием родительского селектора (.class { &:extend() }
).
Проведя процедуру компиляции на выходе мы получим все тот же CSS, который и получили при ручной оптимизации:
.class-1,
.class-2,
.class-3 {
background-color: #fff;
color: #000;
}
Пример 2.4.2
Можно указывать как один селектор для расширения, так и несколько.
.class-1 { background-color: #fff; }
.class-2 { background-color: #fff; }
.selector {
&:extend(.class-1, .class-2);
}
В результате такого объявления класс .selector
будет группироваться и с первым (.class-1
) селектором, и со вторым (.class-2
).
.class-1,
.selector {
background-color: #fff;
}
.class-2,
.selector {
background-color: #fff;
}
Расширение правил
Селекторы можно не только группировать, но и расширять. Все эти громкие слова на самом деле пляшут вокруг все того же :extend()
. Ранее рассматривались примеры, в которых все свойства у селекторов были одинаковыми и это те самые идеальные случаи. На практике такое встречается редко, но все таки встречается. Чаще всего попадаются другие случаи, когда часть свойств совпадают, а часть — нет. В этом случае опять пригодится этот же псевдокласс.
Пример 2.4.3
В студии «Артемка и КО» разрабатывается дизайн для продающего лендинга известной компании, производящей конфеты.
.global-header {
background-color: #fff;
color: #000;
}
.global-navigation {
border: 1px solid #ddd;
}
По дизайну, селектору .global-navigation
полагается белый фон и чёрный цвет у текста. Можно было бы просто скопировать недостающие свойства, но по желанию верстальщика решили использовать :extend()
, тем самым получив недостающие свойства.
.global-header {
background-color: #fff;
color: #000;
}
.global-navigation {
&:extend(.global-header);
border: 1px solid #ddd;
}
По сути своей, это одно и то же, что и группировка селекторов, но я должен был рассказать об этом. Сделано это для того, чтобы вы не подумали о том, что группировать можно лишь те селекторы, у которых совпадают свойства.
Группировка с цепочкой селекторов
Препроцессоры настолько умные, что в состоянии уследить за цепочкой селекторов с одним именем. Делается это с помощью все того же псевдокласса :extend()
, но с добавлением некоего параметра all
.
Пример 2.4.4
Студия «Артемка» получила свои первые правки по макету для компании, производящей конфеты. Заказчик хочет, чтобы подвал сайта имел такие же стили, как и шапка сайта.
.global-header {
background-color: #fff;
.area {
text-align: center;
}
}
.global-header:hover {
background-color: #000;
}
Верстальщик вспоминает о возможности группировки селекторов .global-footer
со всеми селекторами, имеющими имя .global-header
. На ум ему приходит только одно:
.global-footer {
&:extend(.global-header);
}
Однако, после компиляции он получает не совсем желанный результат. Селектор .global-footer
группируется лишь с самым первым селектором, а остальные игнорируются.
.global-header,
.global-footer {
background-color: #fff;
}
.global-header .area {
text-align: center;
}
.global-header:hover {
background-color: #000;
}
Для решения этой проблемы ему необходимо использовать параметр all
, говорящий компилятору о том, что селектор хочет сгруппироваться со всеми совпадающими по имени селекторами. Передать этот параметр нужно следующим образом:
.global-footer {
&:extend(.global-header all);
}
В итоге получается требуемый результат. Студия «Артемка» продолжает работу над проектом, а заказчик продолжает присылать желанные правки.
.global-header,
.global-footer {
background-color: #fff;
}
.global-header .area,
.global-footer .area {
text-align: center;
}
.global-header:hover,
.global-footer:hover {
background-color: #000;
}
Контекстная группировка
Less поддерживает группировку с конкретным селектором. Речь идёт про то, что :extend()
может принимать в качестве цели не только название селектора, но и селектор с необходимой вложенностью, контекстом и некоторыми другими параметрами.
Псевдокласс :extend()
умеет работать с:
- nth:
:extend(:nth-child(n+3))
. - атрибутами:
:extend([title=identifier])
. - псевдоклассами:
:extend(link:visited:hover)
. - псевдоэлементами:
:extend(link:before)
.
Пример 2.4.5
Верстальщик получает макет, в котором стили оформления товаров в каталоге и статей в блоге имеют общие стили, но лишь в шапке.
.item {
background-color: #fff;
border: 1px solid #ddd;
.header {
padding: 25px;
}
}
Ему хочется унаследовать стили .item .header
, но не хочется городить лишнего кода. Приходится использовать контекстную группировку с применением уже знакомого нам псевдокласса :extend()
.
.item {
background-color: #fff;
border: 1px solid #ddd;
.header {
padding: 25px;
}
}
.article {
&:extend(.item .header);
}
После компиляции получается код, который полностью соответствует ожиданиям верстальщика и его требованиям:
.item {
background-color: #fff;
border: 1px solid #ddd;
}
.item .header,
.article {
padding: 25px;
}
Мысли и советы
Пожалуй, это самый объёмный по материалу функционал для изучения, предоставляемый CSS-препроцессором Less. В то же время, это наименее используемый функционал в реальных проектах, так как приходится запоминать имена селекторов для группировки, а при достаточно объёмном проекте это не позволительная роскошь.
Я бы советовал аккуратно работать с :extend()
и использовать его лишь тогда, когда это действительно оправданный шаг. Благодаря известному всем разработчикам фреймворку Bootstrap, я стал использовать :extend()
лишь для группировки селекторов с селектором .clearfix
. Такой подход позволяет исключить появление дополнительных классов в документе, тем самым делая структуру более чистой.