Строки и списки
Экранирование
Компилятор, сам по себе, штука умная. Но даже у умных штук есть проблемы. Например, компилятор не может сходу определить, является ли предлагаемая ему для обработки конструкция валидной. Проще говоря, если конструкция не предназначается компилятору, то может случиться порождение ошибки. Для предотвращения таких проблемных ситуаций, используется экранирование значения переменных, которое было подробнее рассмотрено в главе 3.
Функция кодирования (Escape)
Вместо того, чтобы ещё раз говорить об экранировании, давайте рассмотрим функцию кодирования символов — escape
.
Функция escape
, позволяет закодировать символы, которые могут вызывать проблемы в CSS. Например, такими символами являются: пробел
, #
, ^
, (
, )
, ;
и т.д.
Зачем это может пригодиться в Less? — одним создателям известно. Конечно, можно предположить, что таким образом можно вставлять текст в значение свойства content
или что-то в этом духе, но это не работает, так как требуются кавычки, которые эта функция кодирует. Пусть это останется загадкой.
Я честно пытался найти применение этой функции, но ничего не получилось. Поэтому наслаждайтесь замечательным примером из документации:
escape('a=1') // a%3D1
Форматирование строк
Помимо встроенной функции кодирования, в Less имеется довольно редко используемая функция форматирования строк.
Эта функция позволяет формировать строку, используя управляющие последовательности (%
) в ней. Синтаксис этой функции имеет следующий вид:
@string: %(строка, аргументы...);
Все аргументы, переданные в функцию, являются значениями для заполнителей, кроме первого аргумента. Первый аргумент всегда является строкой, содержащей сами заполнители. Заполнитель — это символ процента (%
) и следующая за ним буква (S, s, D, d, A, a
).
Если в строке указывается прописная буква (A, D, S
), то специальные символы, переданные в строку в значениях, будут экранированы. Исключением являются символы ()'~!
. Строчные буквы (a, d, s
) оставляют специальные символы без изменений.
Заполнители D, d
и A, a
могут быть заменены любым аргументом (цветом, цифрой, выражением), но будут включать в себя кавычки. Заполнители S, s
вычисляют выражение и подставляют его без кавычек.
Например, можно использовать этот функционал, чтобы формировать значение свойства content
:
@string: "В этот замечательный день %S, я хочу сказать вам: %a";
@date: "(28.06.2015)";
@message: в Less так много интересных функций;
.block {
content: %(@string, @date, @message);
}
Компилятор просто подставит строки из переменных в шаблон:
.block {
content: "В этот замечательный день (28.06.2015), я хочу сказать вам: в Less так много интересных функций";
}
Замечание
Для того, чтобы использовать в строке символ процента как обычный символ процента — необходимо просто удвоить его (
%%
).
Функция замены (Replace)
Эта функция позволяет заменить указанное значение в строке на то, что будет передано в аргументах функции. Синтаксис этой функции имеет следующий вид:
@string: replace(строка, паттерн, замещающая строка, флаги);
Под паттерном понимается строка или регулярное выражение, поиск которых будет производиться в переданной строке. Замещающая строка — это обычная строка, которая будет вставлена на место найденных совпадений с паттерном. Соответственно, флаги передаются лишь в том случае, если планируется использовать паттерн как регулярное выражение.
Вот пример, демонстрирующий работу этой функции:
.block {
content: replace("Less имеет много нужных функций", "нужных", "интересных");
}
В приведённом выше примере, слово «нужных» будет заменено на слово «интересных», что в итоге даст довольно правдивую строку:
.block {
content: "Less имеет много интересных функций";
}
Пример 4.2.1
В этом примере будет рассмотрен один из возможных способов применения функции замены значений в строке. Для этого я предлагаю написать примесь, которая задаёт фоновое изображение и его увеличенную версию для дисплеев с большей плотностью пикселей.
.bg(@path, @width, @height) {
background-image: url(@path);
@media only screen and (min-resolution: (1.5 * 96dpi)), only screen and (min-resolution: (1.5 * 1dppx)) {
@retina: replace(@path, "(\.[0-9a-z]+)$", "@2x$1", "i");
background-image: url(@retina);
background-size: @width @height;
}
}
.block {
.bg("../images/header-bg.png", 18px, 18px);
}
Обратите внимание на переменную @retina
, значение которой вычисляется на основе работы функции замены значений в строке. В качестве паттерна при вызове функции используется регулярное выражение, извлекающее из строки расширение файла. Затем к расширению прибавляется строка @2x
, и уже новое значение возвращается в переменную @retina
.
Результат работы этой примеси имеет следующий вид:
.block {
background-image: url("../images/header-bg.png");
}
@media only screen and (min-resolution: 144dpi), only screen and (min-resolution: 1.5dppx) {
.block {
background-image: url("../images/[email protected]");
background-size: 18px 18px;
}
}
Списки
Наиболее интересной возможностью Less, из описанных в этой части, является работа со списками, которые в мире программирования называются массивами.
Списки в Less выглядят следующим образом:
@list: "one", two, three four;
В приведённом мной примере, список состоит из трёх элементов: "one", two и three four.
Препроцессор Less не обязывает вас использовать запятые, то есть список может выглядеть следующим образом:
@list: "one" two three four;
Кавычки считаются вместе с элементом, вокруг которого они поставлены. Они также не обязательны, поэтому их можно опустить, если элемент не состоит из двух и более слов.
Замечание
Элементом списка может являться строка, переменная (исключая наборы правил) и другой список.
Для того, чтобы достать из списка какой-либо элемент, используется функция extract
. Важно запомнить, что нумерация здесь начинается не с 0, как это принято, а с 1.
Допустим, что у нас есть частичный список глав этой книги и нам нужно достать значение текущей главы. Решается эта задача очень просто:
@list: "Основы", "Работа с селекторами, медиа-запросами и файлами", "Переменные и примеси", "Операции со свойствами и встроенные функции";
Для разнообразия применим возможность форматирования текста, описанную выше:
.block {
@currentStatus: e(extract(@list, 4));
content: %("Текущая глава: %a", @currentStatus);
}
.block {
content: "Текущая глава: Операции со свойствами и встроенные функции";
}
Напомню, что обычно функция
e()
применяется для экранирования. Однако, здесь она применяется лишь для того, чтобы избавиться от кавычек, которые являются частью элемента списка.
Помимо функции extract()
, иногда применяется функция для определения длины списка — length()
. Применим её к списку глав:
.block {
content: length(@list);
}
Попробуйте догадаться, что выведет компилятор. Ну конечно же! Четыре:
.block {
content: 4;
}
К сожалению, аналогов других методов, принятых в JavaScript в Less нет.
Пример 4.2.2
Теперь давайте поработаем со списком в более серьёзном ключе. Допустим, что у нас есть список префиксов для селекторов сетки (xs, sm, md, lg) и нам нужно добавить их при построении сетки.
К сожалению, данный пример нельзя продемонстрировать без применения цикла, поэтому сейчас будет немного слегка не очевидной магии. Просто знайте, что на каждой итерации цикла в селектор будет подставляться значение из списка. Более подробно о циклах смотрите в главе 5.
@column-name: col;
@column-count: 4;
@column-prefix: xs, sm, md, lg;
// Генератор селекторов
.generate-class(@indexCount, @indexPrefix: 1) when (@indexPrefix =< length(@column-prefix)) {
// Получаем элемент списка
@prefix: extract(@column-prefix, @indexPrefix);
// Формируем селектор
.@{column-name}-@{prefix}-@{indexCount} {
width: @indexCount * (100% / @column-count);
}
// Порождаем следующую итерацию
.generate-class(@indexCount, @indexPrefix + 1);
}
// Генератор сетки
.make-grid(@indexCount: 1) when (@indexCount =< @column-count) {
// Вызываем генератор селекторов
.generate-class(@indexCount);
// Порождаем следующую итерацию
.make-grid(@indexCount + 1);
}
// Вызываем генератор сетки
.make-grid();
Кстати, в скомпилированном виде это выглядит так:
.col-xs-1 { width: 25%; }
.col-sm-1 { width: 25%; }
.col-md-1 { width: 25%; }
.col-lg-1 { width: 25%; }
/*
* ...
* Здесь ещё восемь классов, которые я убрал ради экономии места
* ...
*/
.col-xs-4 { width: 100%; }
.col-sm-4 { width: 100%; }
.col-md-4 { width: 100%; }
.col-lg-4 { width: 100%; }
Поздравляю с боевым крещением, так как циклы — это самое сложное, что есть в Less. Но не волнуйтесь — мы с ними еще встретимся в следующей главе, где будем говорить о них намного подробнее.