Препроцессор 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 я еще вернусь, но у же в рамках чего-то другого.
А вам большое спасибо за внимание! Желаю вам пережить эту жару с максимальным комфортом!
Ссылки на мои социальные сети, там анонсы постов, некоторые мои короткие записи, мыслишки и всякое на отвлечённые темы:
Заходите куда удобно вам и подписывайтесь! Еще раз спасибо за внимание!