Препроцессор Less — Тренажёр HTML Academy
Разобравшись с вёрсткой переходим к инструментам её ускорения. Мы уже знаем базовые вещи PHP, который формально препроцессор HTML, теперь же займемся CSS и одним из его препроцессоров Less.
Я, кстати, уже писал немножечко про один другой препроцессор CSS — в статье про мобильное приложение для самообучение Webref, там нас познакомили с Sass и его упрощённым вариантом SCSS. Спойлер — отличия от Less всё-таки есть, особенно в синтаксисе, хотя по сути мало что меняется.
О препроцессорах
Препроцессор позволяет подойти к языку разметки или стилей как к языку программирования — с переменными, условиями, циклами и так далее. Это касается и PHP для HTML, который мы разбирали уже достаточно давно, и это же касается Less или других вариантов для CSS.
Почему эти языки называются препроцессорными, я уже как-то давно писал в самом начале про PHP, но если вкратце — это языки которые обрабатывает сервер и трансформирует его в понятный для браузера HTML и CSS.
В случае с Less мы по сути «программируем» стили, уменьшаем количество повторов и, тем самым, упрощаем себе работу. Меньше повторов, меньше времени на написание, больше логики и наглядности. Хотя по началу может показаться с точностью да наоборот.
Возможности Less
Итак, теперь мы не только описываем стили элементов, но и пытаемся построить логику этого описания. Синтаксис самой основы CSS не меняется — все правила, свойства и их значения, что мы разбирали до этого, остаются такими же. Less же, можно сказать, надстройка в виде дополнительных функций.
Переменные
Первое, что можно сделать в Less — это объявить переменную:
@main-color: red; @cintainer-width: 150px;
Один раз объявив переменную, мы можем использовать её в любом месте кода, при этом, поменяв значение переменной — оно поменяется везде. Таким образом, сильно упрощается работа с большим объемом одинаковых параметров.
.card-container {
background-color: @main-color;
width: @container-width;
}
.description {
color: @main-color;
}Переменные можно объявлять даже внутри правил, таким образом они становятся локальными для этого правила и работают только внутри него, то есть использовать эту переменную в другом правиле не получится.
С переменными Less работают стандартные правила области видимости — переменные объявленные вне правил являются глобальными и могут применятся везде, при этом они могут переопределяться на локальные значение:
.card-container {
@container-width: 100px;
background-color: @main-color; /* будет red -глобальное значение */
width: @container-width; /* будет 100px - локальное значение */
}
.description {
@main-color: blue;
color: @main-color; /* будет blue - локальное значение */
}Математические операции
Как и в других языках программирования, в переменные и свойства в Less можно записывать не только какие-то конечные значения — цвет, числовые значения, строки и т. д., но и различные комбинации, модификации, функции и так далее.
Например, самый простой вариант — в Less работают математические операции:
@cintainer-width: 150px; @big-container-width: @container-width + 100; /* 250px */ @par-font-size: 16px; @header-font-soze: @par-font-size * 1.5; /* 16 * 1.5 = 24 */ @cell-wudth: 50%; @mini-cell-width: @cell-width / 2; /* 50% / 2 = 25% */
Два основных нюанса при написании математических операций в Less:
- Вокруг операторов обязательно должны быть пробелы, иначе обработчик может воспринять их за часть строки.
- Единица измерения берётся из первого параметра.
С числовыми значениями вполне всё очевидно, а вот с цветом не совсем — с ним тоже возможны математические операции, но операторы в любом случае будут работать с показателями RGB и влиять на все три цветовых показателя.
При этом неважно как мы зададим цвет — ключевым словом, HEX или как-то еще — операция будет с показателями RGB:
@rgb-color: rgb(110, 27, 255); @keyword-color: red; /* эвкивалент rgb(255, 0, 0) */ @hex-color: #aa3399; /* эквивалент rgb(170, 51, 153) */ @new-rgb-color: @rgb-color + 20; /* = rgb(130, 47, 255) – 255 максимум */ @new-keyword-color: @keyword-color + 20; /* = rgb(255, 20, 20) */ @new-hex-color: @hex-color + 20; /* = rgb(190, 71, 173) */
Цветовые функции
Помимо математических операций в Less существуют и функции. Я уверен их достаточно много, но в тренажёре нас сначала знакомят в основном с цветовыми функциями, влияющими на тон, яркость и насыщенность.
Первая на очереди функция поворота цветового тона spin(), которая очень похожа на CSS-фильтр hue-rotate() и делает по сути тоже самое, но меняет именно значение конкретного цвета в свойстве, а не модифицирует уже отрисованный элемент.
Функция принимает два аргумента — цвет или переменную с цветом и числовое значение угла поворота, причём без указания единицы измерений deg:
@not-red: spin(red, 60); /* повернет на 60deg по часовой на диаграме */
@true-red: spin(@not-red, -60); /* повернёт обратно, против часовой */
.green-box {
background-color: spin(@true-red, 120); /* 120deg от red - зелёный */
}Следующие две функции отвечают за уменьшение и увеличение яркости цвета — darken() и lighten() соответственно. Функции тоже принимают два аргумента, первый — это цвет или переменная с цветом, а вторая значение увеличения яркости в процентах %:
@light-blue: lighten(blue, 50%); @dark-blue: darken(blue, 50%);
Во втором аргументе указывается именно процент воздействия на цвет, а не положение на шкале яркости. То есть при 100% значении darken() получится чёрный цвет, а при 100% значении lighten() получится белый, при этом при значении 0% — цвет не изменится.
И последние две функции из тренажёров отвечающие за уменьшение и увеличение насыщенности цвета — desaturate() и saturate() соответственно. Синтаксис у них такой же как и у яркости:
@more-blue: saturate(blue, 30%); @greyly-blue: desaturate(blue, 50%); @grey: desaturate(blue, 100%); /* 100% desaturate = оттенки серого */
В первом аргументе всех этих функций можно использовать и сами функции, таким образом вкладывать их друг в друга:
@dark-greyly-yellow: darken(desaturate(yellow, 50%), 30%);
Где всё это применимо? В тренажёре нам приводят в пример всплывающие подсказки и их стилизацию — мы задаём лишь один базовый цвет — фиолетовый, а всё остальное будь то цвет текста, фона и рамок даже разных сообщений мы выводим из базового используя вышеописанные функции.
Таким образом меняя всего один параметр — базовый цвет, мы можем поменять палитру всех элементов. Используя эти инструменты по сути можно создавать целые «темы» интерфейса и менять их одним переключателем!
Вложенные правила
Следующие возможности препроцессора связаны с CSS-правилами. Самое простое для понимания — в Less CSS-правила можно вкладывать друг в друга:
.card {
color: @text-color;
background-color: @bg-color;
a {
color: @link-color;
text-decoration: none;
}
}.card {
color: red; /* цвета условные */
background-color: black;
}
.card a {
color: blue;
text-decoration: none;
}Такая древовидная вложенность в Less избавляет код от дублей и делает его более структурным, читаемым и наглядным.
При работе с такой вложенной структурой в Less есть еще один механизм позволяющий обращаться непосредственно к родительскому селектору или к его подстроке:
.button {
&-submit {
color: @btn-text-color;
background-color: @btn-bg-color;
&:hover {
background-color: lighten(@btn-bg-color, 30%);
}
}
&-cancel {
background-color: desaturate(@btn-bg-color, 50%);
}
}Будет преобразовано в CSS как:
.button-submit {
color: white; /* цвета снова условные */
background-color: red;
}
.button-submit:hover {
background-color: lightred;
}
.button-cancel {
background-color: #fa8072;
}Символ амперсанда & приравнивается к строке указанной в родительском селекторе и таким образом можно обращаться сразу к группе селекторов в своем пространстве имён.
Также как и в примере, это используется при работе с псевдоклассами — иначе без подстановки & перед :hover конечный селектор в CSS выглядел бы как .button-submit :hover — именно с пробелом.
Примеси Less
Следующая важная особенность Less — примеси, возможность «примешивать» содержимое одного правила в другой. Если в Less записать:
.big { width: 500px; }
.white { color: white; }
.block {
.big;
.white;
}.big { width: 500px; }
.white { color: white; }
.block {
width: 500px;
color: white;
}Это самый примитивный вариант, однако, примеси это целый новый уровень абстракции, позволяющий создавать по сути чуть ли не функции.
Примесь в её более расширенном понимании — это комплексное Less-правило, которое в итоге не выводится в конечный CSS, а применяется для структурного построения и которому можно даже задать аргументы.
На мой взгляд, примесь действительно похожа на функцию в обёртке CSS синтаксиса — выглядит она как обычный селектор со скобками:
.white() { color: white; } /* объявление примеси */
.text { .white(); } /* применение примеси */При этом в CSS примесь никак не выводится:
.text { color: white; }Скобочки у примеси не просто так — на самом деле, в них можно передавать параметры, которые далее используются в примеси для её построения. Параметрам можно задать значение по умолчанию, в случае если при вызове примеси их не указали:
.colors (@color) { /* параметр без значения по умолчанию */
color: darken(@color, 30%);
background-color: lighten(desaturate(@color, 20%) 20%);
}
.offset(@padding: 10px; @margin: 20px;) { /* со значениями по умолчанию */
padding: @padding;
margin: @margin;
}
.block {
&-1 {
.colors(blue);
.offset(5px; 10px); /* значения сопоставляются по порядку */
}
&-2 {
.colors(green);
.offset();
}
}.block-1 {
color: darkblue;
background-color: lightskyblue;
padding: 5px; /* значения при вызове примеси */
margin: 10px;
}
.block-2 {
color: darkgreen;
background-color: lightseagreen;
padding: 10px; /* значения по умолчанию */
margin: 20px;
}Таким образом мы можем один раз задать какой-то набор свойств в виде примеси и в дальнейшем вызывать его в любом месте передавая только параметры. Особенно хорошо можно прочувствовать полезность примесей если поработать со свойствами типа border-top-left-radius и написать их хотя бы несколько раз в чистом CSS.
Шаблон примеси
Можно пойти дальше и создать не просто какое-то количество разных примесей, а структурировать их и создать шаблоны для однотипных примесей.
Чтобы создать шаблон примеси, достаточно указать его имя в первом аргументе, перед параметрами примеси:
.set-color(@color) { /* примесь */
background-color: @color;
}
.set-font-size(lighten; @color) { /* шаблон примеси */
background-color: lighten(@color, 50%);
}Самый тривиальный пример — шаблонизировать примеси для текста. Мы можем задать какой-то один базовый размер и от него плясать в зависимости от применяемой области.
@base-font-size: 16px;
.set-font-size(@size) {
font-size: @size;
line-height: @size * 1.5;
}
.set-font-size(small, @size) {
font-size: @size / 2;
line-height: @size / 2;
}
.set-font-size(big, @size) {
font-size: @size * 2;
line-height: @size * 2 * 1.2;
}
.promo-header {
.set-font-size(big, @base-font-size);
}
.promo-description {
.set-font-size(@base-font-size);
}
.promo-note {
.set-font-size(small, @base-font-size)
}.promo-header {
font-size: 32px; /* 16 * 2 = 32 */
line-height: 38px; /* 16 * 2 * 1.2 = 32 * 1.2 = 38.4 */
}
.promo-description {
font-size: 16px;
line-height: 24px; /* 16 * 1.5 = 24 */
}
.promo-note {
font-size: 8px; /* 16 / 2 = 8 */
line-height: 8px;
}Таким образом, у нас появляется, своего рода, пространство имён для примесей — лучше для однотипных задач использовать примеси с шаблонами, чем несколько разных примесей с разными названиями.
У шаблонов есть дополнительная фишка — универсальный шаблон, который применяет указанные в нём параметры для всех одноименных примесей. Это полезно в случае если в каком-то наборе шаблонов примесей применяется один и тот же неизменяемый или одинаково изменяемый для всех шаблонов параметр.
Он обозначается зарезервированным именем _@ и на примере шаблонов для текста выше, мы можем, скажем, задать везде одинаковый font-weight:
.set-font-size(_@, @size) {
font-weight: bold;
}В итоге всем элементам, где были применены указанные примеси и их шаблоны будет подставлен этот параметр.
Примесь с условием
Вот мы и дошли до «программируемой» части Less — условные конструкции с примесями! Логика, правда, немного отличается от привычной конструкции в языках программирования — мы не задаём условия «if/else», в которых пишем что будет происходить в их случае.
Я немного порылся в англоязычной документации Less и там эта конструкция называется «Mixin Guards», то бишь «Охрана примеси». Суть, в общем-то, практически не меняется — мы ставим условие выполнения самой примеси с помощью ключевого слова when:
.set-font-size(@size) when (@size < 12px) {
font-weigth: regular;
}Примесь выше сработает только если передаваемое значение, в нашем случае это размер шрифта, окажется меньше 12px.
В условие в скобках можно помещать как параметры самой примеси, так и внешние факторы, например, соответствие каких-то внешних переменных, причем их соответствие проверяется в момент вызова примеси:
.set-font-color(@color) {
color: @color;
}
.set-font-color(@color) when (@bg-color = black) {
color: lighten(@color, 50%);
}
.first-text {
.set-font-color(red); /* сработает безусловная примесь */
}
@bg-color: black; /* теперь условие корректно */
.second-text {
.set-font-color(red); /* сработает условная примесь */
}.first-text {
color: red; /* безусловная примесь */
}
.second-text {
color: lightred; /* примесь с условием */
}Помимо этого, в условии или в «охране», можно использовать функции для проверки типа передаваемых в примесь данных. Грубо говоря, строго типизировать нашу примесь:
.mixin(@param) when (isnumber(@param)) { … }Функций проверки не так уж и много:
isnumber()— из примера выше, проверяет значение — любое числовое значение — просто число, пиксели, проценты и так далее, главное исчисляемое значение.iscolor()— проверка значение — цвет, любой вариант записи — ключевое слово, HEX, RGB и так далее;isstring()— проверка значение — строка, то есть значения свойств обёрнутые в кавычки"..."— различные названия шрифтов, например;iskeyword()— проверка значение — ключевое слово, имеются ввиду ключевые слова в значениях свойств, кроме цветовых —right,center,middleи так далее;isurl()— проверка значение — функцияurl(), то есть проверка на значение-ссылку.
Есть еще несколько дополнительных, проверяющих конкретные единицы измерения — ispixel(), ispercentage() и isem(). Там еще есть парочку, но про них нет смысла пока писать.
Вставки
В Less примеси — это целые правила, которые можно примешать к другим правилам. Но есть и возможность подставлять какие-то отдельные куски правил, свойств, значений, да в общем-то чего угодно. Называется это «вставка» или интерполяция переменных.
В переменную мы можем записать по сути что угодно — число, строку, ключевое слово даже часть названия селектора. То есть, переменную не обязательно использовать только как носитель чего-то значимого с точки зрения CSS, это может быть и часть структуры Less.
Дальше чтобы значение этой переменной подставить в нужном месте используется фигурные скобки вокруг имени — @{var}:
@state: success;
@property: color;
@icon: "question";
.btn-@{state} { /* как часть селектора */
background-color: green;
}
.btn-error {
background-@{property}: red; /* как часть свойства */
}
.btn-help {
background-image: url("/img/icons/@{icon}.png"); /* как часть url */
}.btn-success {
background-color: green;
}
.btn-error {
background-color: red;
}
.btn-help {
background-image: url("/img/icons/question.png");
}Еще одна особенность Less, про которую упомянули в этом уроке, но которая на мой скромный взгляд очень важна — это своеобразное экранирование или такой режим строки, содержимое которой при вызове не изменяется, то есть игнорируется весь Less синтаксис кроме интерполяций.
Задаётся такая строка с помощью кавычек и знака тильды ~"...", это позволяет записывать в строку, а как следствие в переменную или в значение целые выражения и даже свойства с подставляемым значением:
@base-size: 10;
@base-color: red;
@default-border: ~"@{base-size}px solid"; /* интерполяция */
/* почему-то подкрашено в другой цвет, но это тоже переменная */
.border-colored(@color) {
border: @default-border @color;
}
.element {
.border-colored(@base-color);
}Пример прям конкретно говнокодерский, но мне что-то адекватное в голову никак не приходит, но я почему-то уверен, что область применений экранирования очень большая. В CSS выводится вот что:
.element {
border: 10px solid red;
}Без интерполяции значения в экранированную строку переменная с числом не «склеивается» корректно с единицами измерений. То есть 10 и px не объединяются в одну сущность. Хотя, судя по англоязычной документации — это постепенно исправляется и много в каких случаях экранирование уже не нужно.
Циклы
Напоследок разберёмся — можно ли в Less делать циклы? Ответ — можно, но встроенных решений в Less для этого нет. В тренажёре описывается хитрый способ создания цикла с помощью примеси с условием и интерполяцией.
Я не зря писал, что примеси похожи на функции и их как и функцию можно рекурсивно зациклить используя аргумент как счётчик:
.mixin(@n) {
.mixin(@n + 1); /* приращение */
}
.mixin(1);Чтобы цикл был не бесконечный можно использовать примесь с условием, в котором указать момент завершения цикла, например достижение счётчиком определенного значения:
.mixin(@n) when (@n =< 3) { /* при @n > 3 примесь не выполняется */
.mixin(@n + 1);
}
.mixin(1);Вполне себе цикл, который можно использовать, например, для создания селекторов с одинаковым префиксом, но разными суффиксами, используя интерполяцию значения счётчика:
.mixin(@n) when (@n =< 3)
.block-@{n} {
...
}
.mixin(@n + 1);
}
.mixin(1);.block-3 {...}
.block-2 {...}
.block-1 {...}Испытания
Решил вывести их отдельно для обеих частей блока. Все они по сути об одном, плюс я немного переформатировал повествование.
Первое испытание на цветовые функции — у нас уже есть некоторые области с цветами, а отталкиваясь от них нужно заполнить остальные:
Следующее два испытания на понимание работы примесей и их параметров, как со значениями по умолчанию так и без. Плюс, немного вспоминаем про двумерные трансформации:
Третье испытание модифицируется шаблонами примесей:
Четвёртое испытание полностью на понимание работы условных примесей — нужно расставить существующим примесям условия, чтобы они срабатывали только для определённых элементов:
Пятое испытание на создание цикла с использованием интерполяции. Не уверен, что решение того требовало, но я еще использовал и экранирование:
Последнее испытание комбинирует всё пройденное — все примеси созданы, но не применены к элементам, нужно все корректно склеить:
Не самый простой был блок, но очень интересный! У меня, правда, по ходу прохождения возникло много вопросов — например, пресеты цветов можно явно использовать в динамическом изменении цветовой схемы. Как оно будет работать — нужно всё-таки инициировать обновление страницы, чтобы сработал препроцессор и пересобрал все? Или можно как-то с помощью JS это все настроить в динамике в моменте?
Еще я понял, что тут ну прям о-очень небольшая часть от Less, гуляя по документации обнаружил много интересных штук. Так что к Less я еще вернусь, но у же в рамках чего-то другого.
А вам большое спасибо за внимание! Желаю вам пережить эту жару с максимальным комфортом!
Ссылки на мои социальные сети, там анонсы постов, некоторые мои короткие записи, мыслишки и всякое на отвлечённые темы:
Заходите куда удобно вам и подписывайтесь! Еще раз спасибо за внимание!