Специальные параметры и сопоставление шаблонов
Примеси являются очень мощным инструментом в рамках Less. Их возможности практически ограничены лишь фантазией разработчика, а спектр применения довольно широк.
Специальные параметры
Кроме обычных локальных переменных для примеси, можно использовать специальные параметры, которые имеют несколько другое предназначение.
Переменная @arguments
Переменная @arguments
представляет собой синоним для всех переданных в примесь значений при её вызове. Такое поведение может быть полезно при использовании примеси с большим количеством переменных, предназначающихся для одного свойства.
.box-shadow(@x: 0, @y: 0, @blur: 1px, @color: #333) {
-webkit-box-shadow: @arguments;
-moz-box-shadow: @arguments;
box-shadow: @arguments;
}
.big-block {
.box-shadow(2px, 5px);
}
Так как переменная @arguments
содержит в себе значения всех переданных переменных, то результат будет следующим:
.big-block {
-webkit-box-shadow: 2px 5px 1px #333;
-moz-box-shadow: 2px 5px 1px #333;
box-shadow: 2px 5px 1px #333;
}
К счастью, такие примеси уходят в прошлое благодаря плагину Autoprefixer, который является представителем эры постпроцессоров и, наверное, наиболее часто используемым из них.
Переменная @rest
Переменная, позволяющая указывать переменное количество передаваемых параметров. Звучит сложно, но на деле все проще:
.mixin(@width: 152px, @height: 20px, @rest...) {
width: @width;
height: @height;
border: @rest;
}
.class {
.mixin(304px, 40px, 2px, solid, #ddd);
}
Обратите внимание на троеточие (...
) после переменной @rest
. Если бы его не было, то переменная @rest
являлась бы обычной переменной со всеми вытекающими отсюда проблемами в виде ошибки компилятора.
Первые два значения будут присвоены переменным @width
и @height
соответственно, а остальные значения будут доступны переменной @rest
.
.class {
width: 304px;
height: 40px;
border: 2px solid #dddddd;
}
Переменные @rest
и @arguments
можно использовать вместе:
.mixin(@width: 152px, @height: 20px, @rest...) {
content: @arguments;
}
.class {
.mixin(304px, 40px, 2px, solid, #ddd);
}
В этом случае свойство content
получит все переданные переменные:
.class {
content: 304px 40px 2px solid #dddddd;
}
Как и в случае с @arguments
, используется крайне редко, так как такое поведение примесей избыточно и практически не имеет места применения.
Сопоставление шаблонов
Иногда требуется изменять поведение примеси в зависимости от передаваемых в неё параметров. Поведение примеси может зависеть от количества переданных переменных, их значений и некоторых других факторов, о которых будет говориться подробнее в следующей главе.
Я не стал оформлять это как пример, так как здесь идёт объяснение основ сопоставления шаблонов, но вы можете найти описанный здесь код как пример 3.4.5 в архиве, прилагаемом к этой книге.
Допустим, что имеется примесь, которая генерирует цвет фона, шрифта и рамки:
.mixin(@color, @bg, @border-color) {
color: @color;
background-color: @bg;
border: 1px solid @border-color;
}
Требуется изменять цвет и фон блока, например, в зависимости от количества переданных переменных. Если переменная одна, то менять только цвет шрифта, если их две, то менять цвет шрифта и фон, иначе все параметры. Это можно сделать следующим образом:
.mixin(@color) {
color: @color;
}
.mixin(@color, @bg) {
color: @color;
background-color: @bg;
}
.mixin(@color, @bg, @border-color) {
color: @color;
background-color: @bg;
border: 1px solid @border-color;
}
Рассмотрим этот случай подробнее, так как такие конструкции будут часто встречаться в крупных фреймворках и хитрых проектах.
Здесь не играет роли в каком порядке будут объявлены примеси, так как компилятор сам узнает количество переданных значений при вызове примеси и сопоставит их с той примесью, к которой оно подходит. Однако, такая схема работает до тех пор, пока не появится ещё одна примесь с одинаковым количеством переменных, но об этом немного позднее.
Итак, попробуем передать одну переменную:
.test-1 {
.mixin(#333);
}
Сперва может показаться, что такой вызов породит ошибку из-за того, что действует правило «сверху вниз» и использоваться будет последняя примесь. Но это не так.
.test-1 {
color: #333333;
}
Хорошо, здесь сработала первая примесь, которой для работы требуется один параметр.
Попробуем передать все три параметра:
.test-3 {
.mixin(#333, #fff, #ddd);
}
Получим код, который порождает третья примесь:
.test-3 {
color: #333333;
background-color: #ffffff;
border: 1px solid #dddddd;
}
Все это хорошо работает и вроде как даже понятно, но в игру вступает любопытство:
- Что будет, если у всех трёх примесей указаны параметры по умолчанию и примесь вызывается без значений?
- Что будет, если у одной из примесей указаны параметры по умолчанию и примесь вызывается без значений?
- Что будет, если у одной из примесей указаны параметры по умолчанию, у другой частично и примесь вызывается с одним значением?
- Что будет, если объявлены примеси с одинаковым числом параметров?
Ответы на эти вопросы я предлагаю узнать и понять с помощью примеров описанных ниже:
Пример 3.5.1
Что будет, если у всех трёх примесей указаны параметры по умолчанию и примесь вызывается без значений?
Я сокращу количество примесей до двух, чтобы не показывать один и тот же код от примера к примеру.
.mixin(@color: #777) {
color: @color;
}
.mixin(@color: #000, @bg: #fff) {
color: @color;
background-color: @bg;
}
Итак, у всех примесей указаны значения параметров по умолчанию. Можно предположить, что при вызове будут использованы обе примеси, так как обе они подходят под шаблон вызова.
.class {
color: #777777;
color: #000000;
background-color: #ffffff;
}
Пример 3.5.2
Что будет, если у одной из примесей указаны параметры по умолчанию и примесь вызывается без значений?
.mixin(@color: #777) {
color: @color;
}
.mixin(@color, @bg) {
color: @color;
background-color: @bg;
}
При компиляции будет использоваться та примесь, что полностью соответствует шаблону вызова. В нашем случае при вызове не указаны значения переменных и компилятор будет использовать ту примесь, у которой указаны значения по умолчанию.
.class {
color: #777777;
}
Пример 3.5.3
Что будет, если у одной из примесей указаны параметры по умолчанию, у другой частично и примесь вызывается с одним значением?
В этом случае все будет зависеть от того, какой параметр имеет значение по умолчанию у второй примеси.
Допустим, что первый:
.mixin(@color: #777) {
color: @color;
}
.mixin(@color: #333, @bg) {
color: @color;
background-color: @bg;
}
.class {
.mixin(#000);
}
Вместо того, чтобы использовать первую примесь, которая полностью удовлетворяет шаблону вызова, компилятор использует вторую и в ответ отдаёт нам ошибку, говорящую о том, что примеси не хватает передаваемых значений.
SyntaxError: wrong number of arguments for .mixin (1 for 2) in _styles.less on line 11, column 3:
10 .class {
11 .mixin(#000);
12 }
Если же значение по умолчанию указано у второго параметра, то компилятор спокойно выдаст:
.class {
color: #000000;
background-color: #ffffff;
}
Пример 3.5.4
Что будет, если объявлены примеси с одинаковым числом параметров?
Довольно интересный случай, который может сыграть с вами злую шутку или же наоборот помочь вам писать запутанный код.
Вернёмся к полному коду примера 3.4.5 и добавим зловредную примесь. Для наглядности поменяем параметры местами:
.mixin(@color) {
color: @color;
}
.mixin(@color, @bg) {
color: @color;
background-color: @bg;
}
.mixin(@color, @bg, @border-color) {
color: @color;
background-color: @bg;
border: 1px solid @border-color;
}
.mixin(@bg, @color) {
color: @color;
background-color: @bg;
}
Компилятор будет недоволен происходящим, но работу свою он знает и выдаст следующее:
.class {
color: #333333;
background-color: #f5f5f5;
color: #f5f5f5;
background-color: #333333;
}
Получается, что в случае, когда объявлены примеси с одинаковыми именами и количеством параметров на выходе будут иметься свойства сразу двух примесей.
Мысли и советы
Старайтесь не использовать переменные @arguments
и @rest
там, где это не нужно. Такой подход может запутать новых разработчиков вашей команды или даже вас самих.
Сопоставление шаблонов — это, конечно, круто, но не забывайте, что ваш код должен быть элегантным и максимально простым.