Less\Sass → LESS краткий учебник

Less — это CSS препроцессор, который расширяет язык CSS поддержкой:

  • переменных
  • примесей (миксинов, mixins)
  • вложенных правил
  • функций и операторов
  • возможностью импортирования
  • возможностью использовать JavaScript в CSS

Less учебник

Переменные 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`;