Less — это CSS препроцессор, который расширяет язык CSS поддержкой:
- переменных
- примесей (миксинов, mixins)
- вложенных правил
- функций и операторов
- возможностью импортирования
- возможностью использовать JavaScript в CSS
Переменные LESS
Переменные позволяют определить значение (например цвета) в одном месте и повторно использовать его в дальнейшем. Переменные в LESS начинаются с символа @. Пример переменных:
@baseFontSize: 14px;
@baseFontFamily: Helvetica, sans-serif;
@blue: #00214D;
@light-blue: @blue + #111;
@description: "Link ";
@property: color;
@text: "Hello world";
@var: "text";
.header {
color: @light-blue;
font-size: @baseFontSize;
@{property}: #000;
content: @@var; // "Hello world"
}
a::before { content: @description; }
@base-url: "http://sub.domain.com";
background-image: url("@{base-url}/images/bg.png");
// экранирование не валидных выражений
@filter: ~"ms:alwaysHasItsOwnSyntax.For.Stuff()";
border: ~"@{pixels}px" solid blue;
Области видимости переменных в LESS очень схожи с другими языками программирования. Переменные и примеси сначала ищутся в локальной области видимости и если не находятся, компилятор проверяет родительский блок и т.д.
Примеси LESS
Примеси позволяют включать свойства одного класса в другой, просто указав название класса, как свойство. Это метод включить (примешать) новые свойства из одного набора правил в другой. Примеси могут также использоваться как функции и принимать аргументы. Пример:
.bordered { border: 1px solid #cacaca; }
.border-radius(@radius: 10px) {
-webkit-border-radius: @radius;
-moz-border-radius: @radius;
border-radius: @radius;
}
div {
font-size: @baseFontSize;
line-height: @baseLineHeight;
.bordered; // 10px по-умолчанию
.border-radius(5px);
.border-radius(@radius: 20px); // можно с указанием имени параметра
}
Миксин хранит в себе некоторые параметры, и когда он компилируется, все эти параметры внедряются к селектору к которому он применен. Параметры перечисляются через запятую ,
или через точку с запятой ;
. Рекомендуется использовать точку с запятой.
Можно использовать параметризованные примеси, которые не принимают параметров. Это полезно, если вы хотите, чтобы правила, которые описывает примесь не отображались в результирующем CSS, но хотите использовать свойства внутри других правил.
.wrap () {
text-wrap: wrap;
white-space: pre-wrap;
white-space: -moz-pre-wrap;
word-wrap: break-word;
}
pre { .wrap }
// CSS результат (класс .wrap не будет присутствовать в CSS)
pre {
text-wrap: wrap;
white-space: pre-wrap;
white-space: -moz-pre-wrap;
word-wrap: break-word;
}
Переменная @arguments
имеет специальное значение внутри примесей, она содержит все передаваемые при вызове аргументы. Это полезно, когда нужно использовать переданы параметры все вместе.
.box-shadow (@x: 0; @y: 0; @blur: 1px; @color: #000) {
box-shadow: @arguments;
-moz-box-shadow: @arguments;
-webkit-box-shadow: @arguments;
}
div { .box-shadow(2px, 5px); }
// Результат:
div {
box-shadow: 2px 5px 1px #000;
-moz-box-shadow: 2px 5px 1px #000;
-webkit-box-shadow: 2px 5px 1px #000;
}
Можно использовать троеточие ...
если примесь будет иметь переменное количество аргументов. Если указать троеточие после переменной, то все аргументы будут внесены в эту переменную. Переменная @rest
, применение:
.mixin (@color) { color: @color; }
.mixin (@color, @rest...) {
// в @rest попадут аргументы после @color
// в @arguments попадут все аргументы вместе
}
Примеси можно перегружать (изменять поведение в зависимости от переданных аргументов):
.faded (@color) {
color: @color;
}
.faded (@color, @amount) {
color: fade(@color, @amount);
}
А также изменять поведение примеси, основываясь на входящих параметрах.
.mixin(dark; @color) { color: darken(@color, 10%); } .mixin(light; @color) { color: lighten(@color, 10%); } .mixin(@_; @color) { // универсальный шаблон применяется вместе с остальными шаблонами display: block; } @switch: light; .class { .mixin(@switch; #777); // вернет { lighten(#777, 10%); display: block; } }
Примеси с условиями в LESS
Примеси с условиями декларируются в стиле спецификации @media query:
// сделать что-то, когда цвет светлее серого
.mixin (@color) when (lightness(@color) >= 50%) {
background-color: black;
}
// сделать что-то, когда цвет полностью белый
.mixin (@color) when (lightness(@color) = 100%) {
background-color: white;
}
// также можно управлять условиями примесей с помощью внешних переменных
.text-color() when (@theme = light) {
color: white;
}
// проверка значения
.mixin(@param) when (iscolor(@param)) { … }
// по умолчанию только если другие условия не сработали
.mixin (@color) when (default()) { ... }
В LESS есть вcтроенные функции для проверки типа значения. Их можно применять в условиях примесей для проверки типа переданного параметра: iscolor
, isnumber
, isstring
, iskeyword
, isurl
.
Вложенные правила LESS
Они позволяют избавиться от дублирования одинаковых названий в коде и делают его более структурированным. В результате кода становится меньше и он повторяет структуру дерева DOM.
ul {
padding: 0;
li {
font-size: 12px;
// получим "ul li a {}"
a {
color: black;
}
// получим "li.selected"
&.selected {
background: #fafafa;
}
}
}
.button {
&-red { color: red; } // итоговый класс .button-red {}
&-selected, &:hover { color: green; }
&is { color: white } // итоговый класс .buttonis {}
.no-borderradius & { border-radius: none; } // итоговый класс будет .no-borderraidus .button {}
}
Группировка и расширение правил
Специальный псевдокласс :extend()
позволяет производить группировку селекторов за счет перечисления нескольких классов в одном месте (объединение через запятую ,
), при условии, что все эти селекторы имеют общие свойства.
Предположим есть три селектора с одинаковыми свойства:
.header { background-color: #fff; color: #000; } .main { background-color: #fff; color: #000; } .footer { background-color: #fff; color: #000; }
Логичнее их записать так:
.header, .main, .footer { background-color: #fff; color: #000; }
Less предлагает такое решение, он говорит нам, что нужно объявить лишь одни селектор, а других заставить расширить его, для этого используется псевдокласс :extend()
.
.header { background-color: #fff; color: #000; } .main { &:extend(.header); // говорит как бы "расширить через запятую" border: 1px solid #ddd; } .footer:extend(.header) {} // или такой способ записи
На выходе мы получим всё тот же CSS, который и получили при ручной оптимизации + расширенный класс .main:
.header, .main, .footer { background-color: #fff; color: #000; } .main { border: 1px solid #ddd; }
Можно указывать как один селектор для расширения, так и несколько, а также групировать с вложенными селекторами:
.selector { &:extend(.item .header); // группировка с конкретным вложенным селектором &:extend(.class-1, .class-2); // будет группироваться и с первым и со вторым селекторами } .link { background-color: #fff; } .link .area { text-align: center; } .block .link { text-align: left; } .link:hover { background-color: #000; } .selector { // группировать селектор со всеми перечисленными выше // совпадающими по имени селекторами *.link* &:extend(.link all); }
В завершение, пример прибавления свойства через запятую:
.mixin() {
box-shadow+: inset 0 0 10px #555;
}
.myclass {
.mixin();
box-shadow+: 0 0 20px black;
}
// Результат:
.myclass {
box-shadow: inset 0 0 10px #555, 0 0 20px black;
}
Прибавление свойства через пробел:
.mixin() {
transform+_: scale(2);
}
.myclass {
.mixin();
transform+_: rotate(15deg);
}
// Результат:
.myclass {
transform: scale(2) rotate(15deg);
}
Операции в LESS
Математические операции. Less предусматривает возможность использования простых операций: сложения, умножения, разделения, вычисления и т.д. Единицы измерения всегда берутся от первого параметра в выражении.
@baseFontSize: 16px;
@baseWidth: 100px;
@specialWidth: @baseWidth * 2;
@bigFont: (@baseFontSize * 14) - 10;
@rgbColor: rgb(10, 10, 10) + 10; // rgb(20, 20, 20)
blockquote { font-size: @baseFontSize + 4; }
\ операции с цветом
@color: #444 - #111;
h2 { color: @color; }
Пространство имен в LESS
Иногда с целью организации возникает необходимость в группировании переменных или примесей. Для этого используется следующий синтаксис:
#namespace {
.button () {
display: block;
border: 1px solid black;
background-color: grey;
&:hover { background-color: white }
}
.input { ... }
.label { ... }
}
// пример использования
.sidebar a {
color: white;
#namespace > .button;
}
Импорт в LESS
После импорта все переменные и примеси станут доступными в файле, в который они импортируются.
// синтаксис @import [опции, опции] "имя файла"
@import "less/bootstrap.less";
@import (once, less) "variables.less";
@import "style.css";
Существуют следующие опции директивы @input:
reference
: использовать less-файлы, но не выводить содержимое до тех пор, пока оно не будет явно вызвано. Используется в случае, если нужно использовать определённый селектор, а остальное содержимое файла не нужно.inline
: подключить внешний файл, но без обработки компилятором. Пригодится если в подключаемом файле присутствуют не экранированные инструкции которые нужно просто включить а не пытаться обработать (что вызовет ошибку)less
: рассматривать подключаемый файл как less-файл, не зависимо от расширенияcss
: рассматривать подключаемый файл как css-файл, не зависимо от расширенияonce
: запрещает многократное подключение файла (поведение по умолчанию)multiple
: разрешает многократное подключение файлаoptional
: продолжать компиляцию, даже если файл не найден (без вывода ошибок компилятором)
CSS-файлы импортируются, но компилятором не обрабатываются.
Избежать повторного импортирования одного и того самого файла можно также с помощью инструкции @import-once
.
@import (once) — является поведением по умолчанию для @import с версии Less 1.4.0
Циклы в LESS
В Less примеси могут вызывать сами себя. Пример простого цикла в Less:
.loop(@counter) when (@counter > 0) {
.loop((@counter - 1)); // вызывает следующую итерацию
width: (10px * @counter); // код который будет выполнен
}
div {
.loop(5); // вызов цикла
}
// Результат:
div {
width: 10px;
width: 20px;
width: 30px;
width: 40px;
width: 50px;
}
Пример использования цикла в Less для генерации сетки:
.generate-columns(4);
.generate-columns(@n, @i: 1) when (@i =< @n) {
.column-@{i} {
width: (@i * 100% / @n);
}
.generate-columns(@n, (@i + 1));
}
.column-1 {
width: 25%;
}
.column-2 {
width: 50%;
}
.column-3 {
width: 75%;
}
.column-4 {
width: 100%;
}
Использование JavaScript в LESS
Пример:
@var: `"hello".toUpperCase() + '!'`;
// Результат: @var: "HELLO!";
@height: `document.body.clientHeight`;