Spec-Zone.ru › Less 4

Less

Обзор

Подробное руководство по функциям языка LESS. См. Обзор для быстрого обзора LESS.

Для получения подробного руководства по установке и настройке среды LESS, а также документации по разработке для LESS, см.: Использование Less.js.

Переменные

Управление часто используемыми значениями в одном месте.

Обзор

Не редкость видеть одно и то же значение, повторяющееся десятками, а то и сотнями раз в ваших стилях:

a,
.link {
  color: #428bca;
}
.widget {
  color: #fff;
  background: #428bca;
}

Переменные упрощают поддержку кода, предоставляя способ управления этими значениями из одного места:

// Variables
@link-color:        #428bca; // sea blue
@link-color-hover:  darken(@link-color, 10%);

// Usage
a,
.link {
  color: @link-color;
}
a:hover {
  color: @link-color-hover;
}
.widget {
  color: #fff;
  background: @link-color;
}

Интерполяция переменных

Примеры выше были сосредоточены на использовании переменных для управления значениями в правилах CSS, но они также могут использоваться и в других местах, таких как имена селекторов, имена свойств, URL-адреса и @import операторы.

Селекторы

v1.4.0

// Variables
@my-selector: banner;

// Usage
.@{my-selector} {
  font-weight: bold;
  line-height: 40px;
  margin: 0 auto;
}

Компилируется в:

.banner {
  font-weight: bold;
  line-height: 40px;
  margin: 0 auto;
}

URL-адреса

// Variables
@images: "../img";

// Usage
body {
  color: #444;
  background: url("@{images}/white-sand.png");
}

Операторы импорта

v1.4.0

Синтаксис: @import "@{themes}/tidal-wave.less";

Обратите внимание, что до версии v2.0.0 рассматривались только переменные, объявленные в корне или текущем пространстве имен, и при поиске переменной учитывались только текущий файл и вызывающие файлы.

Пример:

// Variables
@themes: "../../src/themes";

// Usage
@import "@{themes}/tidal-wave.less";

Свойства

v1.6.0

@property: color;

.widget {
  @{property}: #0ee;
  background-@{property}: #999;
}

Компилируется в:

.widget {
  color: #0ee;
  background-color: #999;
}

Переменные переменных

В LESS вы можете определить имя переменной, используя другую переменную.

@primary:  green;
@secondary: blue;

.section {
  @color: primary;

  .element {
    color: @@color;
  }
}

Что компилируется в:

.section .element {
  color: green;
}

Ленивая оценка

Переменные не должны объявляться перед использованием.

Действительный фрагмент LESS:

.lazy-eval {
  width: @var;
}

@var: @a;
@a: 9%;

Это тоже допустимый фрагмент LESS:

.lazy-eval {
  width: @var;
  @a: 9%;
}

@var: @a;
@a: 100%;

оба компилируются в:

.lazy-eval {
  width: 9%;
}

При повторном определении переменной используется последнее определение переменной, поиск ведется сверху вниз. Это похоже на CSS, где используется последнее свойство внутри определения для определения значения.

Например:

@var: 0;
.class {
  @var: 1;
  .brass {
    @var: 2;
    three: @var;
    @var: 3;
  }
  one: @var;
}

Компилируется в:

.class {
  one: 1;
}
.class .brass {
  three: 3;
}

По существу, каждое пространство имен имеет «конечное» значение, аналогично свойствам в браузере, как в этом примере с пользовательскими свойствами:

.header {
  --color: white;
  color: var(--color);  // the color is black
  --color: black;
}

Это означает, что, в отличие от других препроцессоров CSS, переменные LESS ведут себя очень похоже на свойства CSS.

Свойства как переменные (НОВОЕ!)

v3.0.0

Вы можете легко обрабатывать свойства как переменные, используя синтаксис $prop. Иногда это может сделать ваш код немного легче.

.widget {
  color: #efefef;
  background-color: $color;
}

Компилируется в:

.widget {
  color: #efefef;
  background-color: #efefef;
}

Обратите внимание, что, как и переменные, LESS выберет последнее свойство в текущем/родительском пространстве имен в качестве «конечного» значения.

.block {
  color: red; 
  .inner {
    background-color: $color; 
  }
  color: blue;  
} 

Компилируется в:

.block {
  color: red; 
  color: blue;  
} 
.block .inner {
  background-color: blue; 
}

Переменные по умолчанию

Иногда мы получаем запросы на переменные по умолчанию — возможность установить переменную только в том случае, если она еще не установлена. Эта функция не требуется, потому что вы можете легко переопределить переменную, поместив определение позже.

Например:

// library
@base-color: green;
@dark-color: darken(@base-color, 10%);

// use of library
@import "library.less";
@base-color: red;

Это работает нормально благодаря ленивой загрузке — @base-color переопределяется, и @dark-color — тёмно-красный.

Родительские селекторы

Ссылка на родительские селекторы с &

Оператор & представляет родительские селекторы вложенного правила и чаще всего используется при применении модифицирующего класса или псевдокласса к существующему селектору:

a {
  color: blue;
  &:hover {
    color: green;
  }
}

результат:

a {
  color: blue;
}

a:hover {
  color: green;
}

Обратите внимание, что без &, вышеприведенный пример приведет к a :hover (селектор потомка, соответствующий элементам, на которые наведен курсор, внутри тегов <a>). Это не то, что мы обычно хотим получить с вложенным :hover.

Оператор «родительских селекторов» имеет множество применений. В основном, каждый раз, когда вам нужно, чтобы селекторы вложенных правил объединялись не по умолчанию. Например, ещё одно типичное применение & — создание повторяющихся имен классов:

.button {
  &-ok {
    background-image: url("ok.png");
  }
  &-cancel {
    background-image: url("cancel.png");
  }

  &-custom {
    background-image: url("custom.png");
  }
}

вывод:

.button-ok {
  background-image: url("ok.png");
}
.button-cancel {
  background-image: url("cancel.png");
}
.button-custom {
  background-image: url("custom.png");
}

Несколько &

& может появляться более одного раза в селекторе. Это позволяет неоднократно ссылаться на родительский селектор без повторения его имени.

.link {
  & + & {
    color: red;
  }

  & & {
    color: green;
  }

  && {
    color: blue;
  }

  &, &ish {
    color: cyan;
  }
}

вывод:

.link + .link {
  color: red;
}
.link .link {
  color: green;
}
.link.link {
  color: blue;
}
.link, .linkish {
  color: cyan;
}

Обратите внимание, что & представляет все родительские селекторы (а не только ближайшего предка), поэтому в следующем примере:

.grand {
  .parent {
    & > & {
      color: red;
    }

    & & {
      color: green;
    }

    && {
      color: blue;
    }

    &, &ish {
      color: cyan;
    }
  }
}

результат:

.grand .parent > .grand .parent {
  color: red;
}
.grand .parent .grand .parent {
  color: green;
}
.grand .parent.grand .parent {
  color: blue;
}
.grand .parent,
.grand .parentish {
  color: cyan;
}

Изменение порядка селекторов

Полезно добавить селектор перед унаследованными (родительскими) селекторами. Это можно сделать, поместив & после текущего селектора. Например, при использовании Modernizr вы можете задать различные правила в зависимости от поддерживаемых функций:

.header {
  .menu {
    border-radius: 5px;
    .no-borderradius & {
      background-image: url('images/button-background.png');
    }
  }
}

Селектор .no-borderradius & добавит .no-borderradius к своему родителю .header .menu для формирования .no-borderradius .header .menu на выходе:

.header .menu {
  border-radius: 5px;
}
.no-borderradius .header .menu {
  background-image: url('images/button-background.png');
}

Комбинаторный взрыв

& также можно использовать для генерации всех возможных перестановок селекторов в списке, разделённом запятыми:

p, a, ul, li {
  border-top: 2px dotted #366;
  & + & {
    border-top: 0;
  }
}

Это расширяется до всех возможных (16) комбинаций указанных элементов:

p,
a,
ul,
li {
  border-top: 2px dotted #366;
}
p + p,
p + a,
p + ul,
p + li,
a + p,
a + a,
a + ul,
a + li,
ul + p,
ul + a,
ul + ul,
ul + li,
li + p,
li + a,
li + ul,
li + li {
  border-top: 0;
}

Расширение

Extend — это псевдокласс LESS, который объединяет селектор, к которому он применён, с селекторами, соответствующими тому, на что он ссылается.

Выпущено v1.4.0

nav ul {
  &:extend(.inline);
  background: blue;
}

В наборе правил выше селектор :extend применит «расширяющий селектор» (nav ul) к классу .inline везде, где появляется класс .inline. Блок объявления останется без изменений, но без ссылки на расширение (поскольку расширение не является css).

Таким образом, следующее:

nav ul {
  &:extend(.inline);
  background: blue;
}
.inline {
  color: red;
}

Выводит

nav ul {
  background: blue;
}
.inline,
nav ul {
  color: red;
}

Обратите внимание, как селектор nav ul:extend(.inline) выводится как nav ul — расширение удаляется перед выводом, а блок селектора остается без изменений. Если в этом блоке нет свойств, то он удаляется из вывода (но расширение всё ещё может повлиять на другие селекторы).

Синтаксис расширения

Расширение либо присоединяется к селектору, либо размещается в наборе правил. Оно выглядит как псевдокласс с параметром селектора, за которым необязательно следует ключевое слово all:

Пример:

.a:extend(.b) {}

// the above block does the same thing as the below block
.a {
  &:extend(.b);
}
.c:extend(.d all) {
  // extends all instances of ".d" e.g. ".x.d" or ".d.x"
}
.c:extend(.d) {
  // extends only instances where the selector will be output as just ".d"
}

Он может содержать один или несколько классов для расширения, разделённых запятыми.

Пример:

.e:extend(.f) {}
.e:extend(.g) {}

// the above and the below do the same thing
.e:extend(.f, .g) {}

Присоединение расширения к селектору

Расширение, присоединённое к селектору, выглядит как обычный псевдокласс с параметром селектора. Селектор может содержать несколько блоков расширения, но все расширения должны находиться в конце селектора.

  • Расширение после селектора: pre:hover:extend(div pre).
  • Пробел между селектором и расширением разрешён: pre:hover :extend(div pre).
  • Разрешено несколько расширений: pre:hover:extend(div pre):extend(.bucket tr) — Примечание: это то же самое, что и pre:hover:extend(div pre, .bucket tr)
  • Это НЕ разрешено: pre:hover:extend(div pre).nth-child(odd). Расширение должно быть последним.

Если набор правил содержит несколько селекторов, любое из них может иметь ключевое слово расширения. Несколько селекторов с расширением в одном наборе правил:

.big-division,
.big-bag:extend(.bag),
.big-bucket:extend(.bucket) {
  // body
}

Расширение внутри набора правил

Расширение можно разместить в теле набора правил с помощью синтаксиса &:extend(selector). Размещение расширения в теле — это сокращение для его размещения в каждом отдельном селекторе этого набора правил.

Расширение внутри тела:

pre:hover,
.some-class {
  &:extend(div pre);
}

ровно то же самое, что и добавление расширения после каждого селектора:

pre:hover:extend(div pre),
.some-class:extend(div pre) {}

Расширение вложенных селекторов

Расширение может соответствовать вложенным селекторам. Последовательность LESS:

Пример:

.bucket {
  tr { // nested ruleset with target selector
    color: blue;
  }
}
.some-class:extend(.bucket tr) {} // nested ruleset is recognized

Выводит

.bucket tr,
.some-class {
  color: blue;
}

По существу, расширение анализирует скомпилированный CSS, а не исходный LESS.

Пример:

.bucket {
  tr & { // nested ruleset with target selector
    color: blue;
  }
}
.some-class:extend(tr .bucket) {} // nested ruleset is recognized

Выводит

tr .bucket,
.some-class {
  color: blue;
}

Точное соответствие с расширением

Расширение по умолчанию ищет точное соответствие между селекторами. Имеет значение, использует ли селектор ведущую звездочку или нет. Не имеет значения, что два выражения nth имеют одинаковый смысл, они должны иметь одинаковую форму, чтобы соответствовать. Единственным исключением являются кавычки в селекторе атрибута; LESS понимает, что они имеют одинаковый смысл и соответствует им.

Пример:

.a.class,
.class.a,
.class > .a {
  color: blue;
}
.test:extend(.class) {} // this will NOT match the any selectors above

Ведущая звездочка имеет значение. Селекторы *.class и .class эквивалентны, но расширение не будет соответствовать им:

*.class {
  color: blue;
}
.noStar:extend(.class) {} // this will NOT match the *.class selector

Выводит

*.class {
  color: blue;
}

Порядок псевдоклассов имеет значение. Селекторы link:hover:visited и link:visited:hover соответствуют одному и тому же набору элементов, но расширение рассматривает их как разные:

link:hover:visited {
  color: blue;
}
.selector:extend(link:visited:hover) {}

Выводит

link:hover:visited {
  color: blue;
}

Выражение nth

Форма выражения nth имеет значение. Выражения nth 1n+3 и n+3 эквивалентны, но расширение не будет соответствовать им:

:nth-child(1n+3) {
  color: blue;
}
.child:extend(:nth-child(n+3)) {}

Выводит

:nth-child(1n+3) {
  color: blue;
}

Тип кавычек в селекторе атрибута не имеет значения. Все следующие эквивалентны.

[title=identifier] {
  color: blue;
}
[title='identifier'] {
  color: blue;
}
[title="identifier"] {
  color: blue;
}

.noQuote:extend([title=identifier]) {}
.singleQuote:extend([title='identifier']) {}
.doubleQuote:extend([title="identifier"]) {}

Выводит

[title=identifier],
.noQuote,
.singleQuote,
.doubleQuote {
  color: blue;
}

[title='identifier'],
.noQuote,
.singleQuote,
.doubleQuote {
  color: blue;
}

[title="identifier"],
.noQuote,
.singleQuote,
.doubleQuote {
  color: blue;
}

Расширение «all»

Когда вы указываете ключевое слово all в последнем аргументе расширения, вы говорите LESS, что этот селектор должен соответствовать другой части селектора. Селектор будет скопирован, а сопоставленная часть селектора будет заменена расширением, создавая новый селектор.

Пример:

.a.b.test,
.test.c {
  color: orange;
}
.test {
  &:hover {
    color: green;
  }
}

.replacement:extend(.test all) {}

Выводит

.a.b.test,
.test.c,
.a.b.replacement,
.replacement.c {
  color: orange;
}
.test:hover,
.replacement:hover {
  color: green;
}

Можно представить этот режим работы как по существу неразрушающий поиск и замену.

Интерполяция селекторов с Extend

Extend не может сопоставлять селекторы с переменными. Если селектор содержит переменную, extend ее проигнорирует.

Однако extend может быть присоединен к интерполированному селектору.

Селектор с переменной не будет сопоставлен:

@variable: .bucket;
@{variable} { // interpolated selector
  color: blue;
}
.some-class:extend(.bucket) {} // does nothing, no match is found

и extend с переменной в целевом селекторе не соответствует ничему:

.bucket {
  color: blue;
}
.some-class:extend(@{variable}) {} // interpolated selector matches nothing
@variable: .bucket;

Оба приведенных выше примера компилируются в:

.bucket {
  color: blue;
}

Однако, :extend прикрепленный к интерполированному селектору работает:

.bucket {
  color: blue;
}
@{variable}:extend(.bucket) {}
@variable: .selector;

компилируется в:

.bucket, .selector {
  color: blue;
}

Ограничение области действия / Extend внутри @media

В настоящее время :extend внутри @media объявления будет соответствовать только селекторам внутри того же объявления @media:

@media print {
  .screenClass:extend(.selector) {} // extend inside media
  .selector { // this will be matched - it is in the same media
    color: black;
  }
}
.selector { // ruleset on top of style sheet - extend ignores it
  color: red;
}
@media screen {
  .selector {  // ruleset inside another media - extend ignores it
    color: blue;
  }
}

компилируется в:

@media print {
  .selector,
  .screenClass { /*  ruleset inside the same media was extended */
    color: black;
  }
}
.selector { /* ruleset on top of style sheet was ignored */
  color: red;
}
@media screen {
  .selector { /* ruleset inside another media was ignored */
    color: blue;
  }
}

Примечание: расширение не соответствует селекторам внутри вложенного @media объявления:

@media screen {
  .screenClass:extend(.selector) {} // extend inside media
  @media (min-width: 1023px) {
    .selector {  // ruleset inside nested media - extend ignores it
      color: blue;
    }
  }
}

Это компилируется в:

@media screen and (min-width: 1023px) {
  .selector { /* ruleset inside another nested media was ignored */
    color: blue;
  }
}

Селектор extend верхнего уровня соответствует всему, включая селекторы внутри вложенных @media:

@media screen {
  .selector {  /* ruleset inside nested media - top level extend works */
    color: blue;
  }
  @media (min-width: 1023px) {
    .selector {  /* ruleset inside nested media - top level extend works */
      color: blue;
    }
  }
}

.topLevel:extend(.selector) {} /* top level extend matches everything */

компилируется в:

@media screen {
  .selector,
  .topLevel { /* ruleset inside media was extended */
    color: blue;
  }
}
@media screen and (min-width: 1023px) {
  .selector,
  .topLevel { /* ruleset inside nested media was extended */
    color: blue;
  }
}

Обнаружение дублирования

В настоящее время обнаружения дублирования нет.

Пример:

.alert-info,
.widget {
  /* declarations */
}

.alert:extend(.alert-info, .widget) {}

Выходные данные

.alert-info,
.widget,
.alert,
.alert {
  /* declarations */
}

Сценарии использования для Extend

Классический случай использования

Классический случай использования — это избежание добавления базового класса. Например, если у вас есть

.animal {
  background-color: black;
  color: white;
}

и вы хотите иметь подтип животного, который перезаписывает цвет фона, у вас есть два варианта, во-первых, измените свой HTML

<a class="animal bear">Bear</a>
.animal {
  background-color: black;
  color: white;
}
.bear {
  background-color: brown;
}

или используйте упрощённый HTML и используйте extend в вашем less. например:

<a class="bear">Bear</a>
.animal {
  background-color: black;
  color: white;
}
.bear {
  &:extend(.animal);
  background-color: brown;
}

Сокращение размера CSS

Mixins копируют все свойства в селектор, что может привести к ненужному дублированию. Поэтому вы можете использовать extend вместо mixins, чтобы перенести селектор к свойствам, которые вы хотите использовать, что приводит к меньшему генерируемому CSS.

Пример - с mixin:

.my-inline-block() {
  display: inline-block;
  font-size: 0;
}
.thing1 {
  .my-inline-block;
}
.thing2 {
  .my-inline-block;
}

Выходные данные

.thing1 {
  display: inline-block;
  font-size: 0;
}
.thing2 {
  display: inline-block;
  font-size: 0;
}

Пример (с extends):

.my-inline-block {
  display: inline-block;
  font-size: 0;
}
.thing1 {
  &:extend(.my-inline-block);
}
.thing2 {
  &:extend(.my-inline-block);
}

Выходные данные

.my-inline-block,
.thing1,
.thing2 {
  display: inline-block;
  font-size: 0;
}

Объединение стилей / Более продвинутый Mixin

Еще один случай использования — как альтернатива mixin — поскольку mixins могут использоваться только с простыми селекторами, если у вас есть два разных блока HTML, но вам нужно применить одни и те же стили к обоим, вы можете использовать extends для связи двух областей.

Пример:

li.list > a {
  // list styles
}
button.list-style {
  &:extend(li.list > a); // use the same list styles
}

Merge

Объединение свойств

Функция merge позволяет агрегировать значения из нескольких свойств в список, разделенный запятыми или пробелами, под одним свойством. merge полезно для таких свойств, как background и transform.

Запятая

Добавить к значению свойства запятую

Выпущено v1.5.0

Пример:

.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;
}

Пробел

Добавить к значению свойства пробел

Выпущено v1.7.0

Пример:

.mixin() {
  transform+_: scale(2);
}
.myclass {
  .mixin();
  transform+_: rotate(15deg);
}

Выходные данные

.myclass {
  transform: scale(2) rotate(15deg);
}

Чтобы избежать любых непреднамеренных соединений, merge требует явного + или +_ флага для каждого ожидающего объявления.

Mixins

"Вставка" свойств из существующих стилей

Вы можете вставлять селекторы классов и селекторы id, например:

.a, #b {
  color: red;
}
.mixin-class {
  .a();
}
.mixin-id {
  #b();
}

что приводит к:

.a, #b {
  color: red;
}
.mixin-class {
  color: red;
}
.mixin-id {
  color: red;
}

Исторически, скобки в вызове mixin необязательны, но необязательные скобки устарели и будут обязательны в будущих выпусках.

.a(); 
.a;    // currently works, but deprecated; don't use
.a (); // white-space before parentheses is also deprecated

Mixins со скобками

Если вы хотите создать mixin, но не хотите, чтобы этот mixin был в вашем выводе CSS, поместите скобки после определения mixin.

.my-mixin {
  color: black;
}
.my-other-mixin() {
  background: white;
}
.class {
  .my-mixin();
  .my-other-mixin();
}

выходные данные

.my-mixin {
  color: black;
}
.class {
  color: black;
  background: white;
}

Селекторы в Mixins

Mixins могут содержать больше, чем просто свойства, они также могут содержать селекторы.

Например:

.my-hover-mixin() {
  &:hover {
    border: 1px solid red;
  }
}
button {
  .my-hover-mixin();
}

Выходные данные

button:hover {
  border: 1px solid red;
}

Пространства имен

Если вы хотите вставить свойства mixin внутри более сложного селектора, вы можете указать несколько идентификаторов или классов.

#outer() {
  .inner {
    color: red;
  }
}

.c {
  #outer.inner();
}

Примечание: устаревший синтаксис Less допускает > и пробелы между именами пространств имен и mixins. Этот синтаксис устарел и может быть удален. В настоящее время они делают то же самое.

#outer > .inner(); // deprecated
#outer .inner();   // deprecated
#outer.inner();    // preferred

Использование именованных пространств имен для mixins позволяет уменьшить конфликты с другими библиотечными mixins или пользовательскими mixins, но также может быть способом "организовать" группы mixins.

Пример:

#my-library {
  .my-mixin() {
    color: black;
  }
}
// which can be used like this
.class {
  #my-library.my-mixin();
}

Защищённые пространства имён

Если у пространства имен есть сторож, mixins, определённые им, используются только если условие сторожа истинно. Сторож пространства имен оценивается точно так же, как сторож mixin, поэтому следующие два mixins работают одинаково:

#namespace when (@mode = huge) {
  .mixin() { /* */ }
}

#namespace {
  .mixin() when (@mode = huge) { /* */ }
}

Функция default предполагается иметь одинаковое значение для всех вложенных пространств имен и mixins. Следующий mixin никогда не оценивается; одно из его условий сторожей гарантированно ложно:

#sp_1 when (default()) {
  #sp_2 when (default()) {
    .mixin() when not(default()) { /* */ }
  }
}

Ключевое слово !important

Используйте ключевое слово !important после вызова mixin, чтобы пометить все унаследованные свойства как !important:

Пример:

.foo (@bg: #f5f5f5; @color: #900) {
  background: @bg;
  color: @color;
}
.unimportant {
  .foo();
}
.important {
  .foo() !important;
}

Результаты:

.unimportant {
  background: #f5f5f5;
  color: #900;
}
.important {
  background: #f5f5f5 !important;
  color: #900 !important;
}

Параметрические Mixins

Как передавать аргументы mixins

Mixins также могут принимать аргументы, которые являются переменными, передаваемыми в блок селекторов при его включении.

Например:

.border-radius(@radius) {
  -webkit-border-radius: @radius;
     -moz-border-radius: @radius;
          border-radius: @radius;
}

И вот как мы можем включить его в различные наборы правил:

#header {
  .border-radius(4px);
}
.button {
  .border-radius(6px);
}

Параметрические mixins также могут иметь значения по умолчанию для своих параметров:

.border-radius(@radius: 5px) {
  -webkit-border-radius: @radius;
     -moz-border-radius: @radius;
          border-radius: @radius;
}

Теперь мы можем вызвать его так:

#header {
  .border-radius();
}

И он будет включать радиус границы 5px.

Вы также можете использовать параметрические mixins, которые не принимают параметров. Это полезно, если вы хотите скрыть набор правил из вывода CSS, но хотите включить его свойства в другие наборы правил:

.wrap() {
  text-wrap: wrap;
  white-space: -moz-pre-wrap;
  white-space: pre-wrap;
  word-wrap: break-word;
}

pre { .wrap() }

Что выведет:

pre {
  text-wrap: wrap;
  white-space: -moz-pre-wrap;
  white-space: pre-wrap;
  word-wrap: break-word;
}

Разделители параметров

В настоящее время параметры разделяются либо точкой с запятой, либо запятой.

Изначально параметры разделялись только запятыми, но позже была добавлена точка с запятой для поддержки передачи значений списков, разделенных запятыми, в отдельные аргументы.

  • два аргумента, и каждый содержит список, разделенный запятыми: .name(1, 2, 3; something, else),
  • три аргумента, и каждый содержит одно число: .name(1, 2, 3),
  • использование фиктивной точки с запятой для создания вызова mixin с одним аргументом, содержащим список CSS, разделенный запятыми: .name(1, 2, 3;),
  • значение по умолчанию, разделенное запятыми: .name(@param1: red, blue;).
  • Начиная с Less 4.0, вы можете обернуть значение списка с помощью скобок [~()], например .name(@param1: ~(red, blue)). Это аналогично синтаксису экранирования кавычками: ~"quote"

Перегрузка mixins

Разрешено определять несколько mixins с одинаковым именем и количеством параметров. Less будет использовать свойства всех, которые могут применяться. Если вы использовали mixin с одним параметром, например .mixin(green);, тогда будут использоваться свойства всех mixins с ровно одним обязательным параметром:

.mixin(@color) {
  color-1: @color;
}
.mixin(@color, @padding: 2) {
  color-2: @color;
  padding-2: @padding;
}
.mixin(@color, @padding, @margin: 2) {
  color-3: @color;
  padding-3: @padding;
  margin: @margin @margin @margin @margin;
}
.some .selector div {
  .mixin(#008000);
}

компилируется в:

.some .selector div {
  color-1: #008000;
  color-2: #008000;
  padding-2: 2;
}

Именованные параметры

Ссылка на mixin может предоставить значения параметров по их именам, а не только по позициям. Любой параметр может быть указан по имени, и их не нужно располагать в особом порядке:

.mixin(@color: black; @margin: 10px; @padding: 20px) {
  color: @color;
  margin: @margin;
  padding: @padding;
}
.class1 {
  .mixin(@margin: 20px; @color: #33acfe);
}
.class2 {
  .mixin(#efca44; @padding: 40px);
}

компилируется в:

.class1 {
  color: #33acfe;
  margin: 20px;
  padding: 20px;
}
.class2 {
  color: #efca44;
  margin: 10px;
  padding: 40px;
}

Переменная @arguments

@arguments имеет особое значение внутри mixins, она содержит все аргументы, переданные при вызове mixin. Это полезно, если вы не хотите работать с отдельными параметрами:

.box-shadow(@x: 0, @y: 0, @blur: 1px, @color: #000) {
  -webkit-box-shadow: @arguments;
     -moz-box-shadow: @arguments;
          box-shadow: @arguments;
}
.big-block {
  .box-shadow(2px, 5px);
}

Что приводит к:

.big-block {
  -webkit-box-shadow: 2px 5px 1px #000;
     -moz-box-shadow: 2px 5px 1px #000;
          box-shadow: 2px 5px 1px #000;
}

Расширенные аргументы и переменная @rest

Вы можете использовать ... если вы хотите, чтобы ваш mixin принимал переменное количество аргументов. Использование этого после имени переменной назначит эти аргументы переменной.

.mixin(...) {        // matches 0-N arguments
.mixin() {           // matches exactly 0 arguments
.mixin(@a: 1) {      // matches 0-1 arguments
.mixin(@a: 1, ...) { // matches 0-N arguments
.mixin(@a, ...) {    // matches 1-N arguments

Кроме того:

.mixin(@a, @rest...) {
   // @rest is bound to arguments after @a
   // @arguments is bound to all arguments
}

Сопоставление с образцом

Иногда вам может понадобиться изменить поведение mixin на основе параметров, которые вы передаете ему. Начнём с чего-то простого:

.mixin(@s, @color) { ... }

.class {
  .mixin(@switch, #888);
}

Теперь предположим, что мы хотим, чтобы .mixin вело себя по-разному в зависимости от значения @switch, мы могли бы определить .mixin следующим образом:

.mixin(dark, @color) {
  color: darken(@color, 10%);
}
.mixin(light, @color) {
  color: lighten(@color, 10%);
}
.mixin(@_, @color) {
  display: block;
}

Теперь, если мы запустим:

@switch: light;

.class {
  .mixin(@switch, #888);
}

Мы получим следующий CSS:

.class {
  color: #a2a2a2;
  display: block;
}

где цвет, переданный .mixin, был осветлен. Если значение @switch было dark, результат будет более тёмным цветом.

Вот что произошло:

  • Первое определение mixin не совпало, потому что оно ожидало dark в качестве первого аргумента.
  • Второе определение mixin совпало, потому что оно ожидало light.
  • Третье определение mixin совпало, потому что оно ожидало любое значение.

Использовались только совпавшие определения mixins. Переменные соответствуют и привязываются к любому значению. Всё, что не является переменной, соответствует только значению, равному ей.

Мы также можем сопоставлять по арности, вот пример:

.mixin(@a) {
  color: @a;
}
.mixin(@a, @b) {
  color: fade(@a, @b);
}

Теперь, если мы вызовем .mixin с одним аргументом, мы получим вывод первого определения, но если мы вызовем его с двумя аргументами, мы получим второе определение, а именно @a с затуханием до @b.

END_OF_DOCUMENT_MARKER

Использование миксинов как функций

Выбор свойств и переменных из вызовов миксина

Доступ к свойствам/значениям

Выпущено v3.5.0

Начиная с Less 3.5, вы можете использовать доступ к свойствам/значениям для выбора значения из правил оценённого миксина. Это позволяет использовать миксины аналогично функциям.

Пример:

.average(@x, @y) {
  @result: ((@x + @y) / 2);
}

div {
  // call a mixin and look up its "@result" value
  padding: .average(16px, 50px)[@result];
}

Результат:

div {
  padding: 33px;
}

Переопределение значений миксина

Если у вас несколько соответствующих миксинов, все правила оцениваются и объединяются, и возвращается последнее соответствующее значение с этим идентификатором. Это похоже на каскад в CSS, и это позволяет «переопределять» значения миксина.

// library.less
#library() {
  .mixin() {
    prop: foo;
  }
}

// customize.less
@import "library";
#library() {
  .mixin() {
    prop: bar;
  }
}

.box {
  my-value: #library.mixin[prop];
}

Вывод:

.box {
  my-value: bar;
}

Безымянные поиски

Если вы не указываете значение поиска в [@lookup] и вместо этого пишете [] после вызова миксина или набора правил, все значения будут каскадироваться, и будет выбрано последнее объявленное значение.

Значение: миксин усреднения из приведенного выше примера можно записать как:

.average(@x, @y) {
  @result: ((@x + @y) / 2);
}

div {
  // call a mixin and look up its final value
  padding: .average(16px, 50px)[];
}

Вывод такой же:

div {
  padding: 33px;
}

Такое же поведение каскадирования справедливо для наборов правил или переменных, связанных с вызовами миксинов.

@dr: {
  value: foo;
}
.box {
  my-value: @dr[];
}

Это выведет:

.box {
  my-value: foo;
}

Разблокировка миксинов и переменных в области вызывающего кода

УСТЕРЕЖДЕННЫЙ - Используйте доступ к свойствам/значениям

Переменные и миксины, определённые в миксине, видны и могут быть использованы в области вызывающего кода. Есть только одно исключение: переменная не копируется, если вызывающий код содержит переменную с тем же именем (включая переменные, определённые другим вызовом миксина). Защищаются только переменные, присутствующие в локальной области вызывающего кода. Переменные, унаследованные из родительских областей, переопределяются.

Примечание: это поведение устарело, и в будущем переменные и миксины не будут сливаться в область вызывающего кода таким образом.

Пример:

.mixin() {
  @width:  100%;
  @height: 200px;
}

.caller {
  .mixin();
  width:  @width;
  height: @height;
}

Результат:

.caller {
  width:  100%;
  height: 200px;
}

Переменные, определённые непосредственно в области вызывающего кода, не могут быть переопределены. Однако переменные, определённые в родительской области вызывающего кода, не защищены и будут переопределены:

.mixin() {
  @size: in-mixin;
  @definedOnlyInMixin: in-mixin;
}

.class {
  margin: @size @definedOnlyInMixin;
  .mixin();
}

@size: globaly-defined-value; // callers parent scope - no protection

Результат:

.class {
  margin: in-mixin in-mixin;
}

Наконец, миксин, определённый в миксине, также действует как возвращаемое значение:

.unlock(@value) { // outer mixin
  .doSomething() { // nested mixin
    declaration: @value;
  }
}

#namespace {
  .unlock(5); // unlock doSomething mixin
  .doSomething(); //nested mixin was copied here and is usable
}

Результат:

#namespace {
  declaration: 5;
}

Рекурсивные миксины

Создание циклов

В Less миксин может вызывать сам себя. Такие рекурсивные миксины, в сочетании с Выражениями защиты и Сопоставлением шаблонов, могут использоваться для создания различных итерационных/циклических структур.

Пример:

.loop(@counter) when (@counter > 0) {
  .loop((@counter - 1));    // next iteration
  width: (10px * @counter); // code for each iteration
}

div {
  .loop(5); // launch the loop
}

Вывод:

div {
  width: 10px;
  width: 20px;
  width: 30px;
  width: 40px;
  width: 50px;
}

Общий пример использования рекурсивного цикла для генерации классов CSS-сетки:

.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%;
}

Защиты миксинов

Защиты полезны, когда вы хотите сопоставить выражения, а не простые значения или арность. Если вы знакомы с функциональным программированием, вы, вероятно, уже сталкивались с ними.

Стремясь как можно ближе остаться к декларативной природе CSS, Less принял решение реализовать условное выполнение с помощью защищённых миксинов вместо if/else операторов в духе спецификаций функций запроса @media.

Начнём с примера:

.mixin(@a) when (lightness(@a) >= 50%) {
  background-color: black;
}
.mixin(@a) when (lightness(@a) < 50%) {
  background-color: white;
}
.mixin(@a) {
  color: @a;
}

Ключевое слово when, которое вводит последовательность защиты (здесь только одна защита). Теперь, если мы выполним следующий код:

.class1 { .mixin(#ddd) }
.class2 { .mixin(#555) }

Вот что мы получим:

.class1 {
  background-color: black;
  color: #ddd;
}
.class2 {
  background-color: white;
  color: #555;
}

Операторы сравнения защиты

Полный список операторов сравнения, используемых в защитах: >, >=, =, =<, <. Кроме того, ключевое слово true является единственным истинным значением, делая эти два миксина эквивалентными:

.truth(@a) when (@a) { ... }
.truth(@a) when (@a = true) { ... }

Любое значение, отличное от ключевого слова true, является ложным:

.class {
  .truth(40); // Will not match any of the above definitions.
}

Обратите внимание, что вы также можете сравнивать аргументы друг с другом или с неаргументами:

@media: mobile;

.mixin(@a) when (@media = mobile) { ... }
.mixin(@a) when (@media = desktop) { ... }

.max(@a; @b) when (@a > @b) { width: @a }
.max(@a; @b) when (@a < @b) { width: @b }

Логические операторы защиты

Вы можете использовать логические операторы с защитами. Синтаксис основан на CSS-запросах медиа.

Используйте ключевое слово and для объединения защит:

.mixin(@a) when (isnumber(@a)) and (@a > 0) { ... }

Вы можете эмулировать оператор или, разделяя защиты запятой ,. Если какое-либо из защит оценивается как истинное, это считается совпадением:

.mixin(@a) when (@a > 10), (@a < -10) { ... }

Используйте ключевое слово not для отрицания условий:

.mixin(@b) when not (@b > 0) { ... }

Функции проверки типа

Наконец, если вы хотите сопоставить миксины на основе типа значения, вы можете использовать функции is.

.mixin(@a; @b: 0) when (isnumber(@b)) { ... }
.mixin(@a; @b: black) when (iscolor(@b)) { ... }

Вот основные функции проверки типа:

  • iscolor
  • isnumber
  • isstring
  • iskeyword
  • isurl

Если вы хотите проверить, является ли значение числом в определённой единице измерения, помимо его численного типа, вы можете использовать один из следующих операторов:

  • ispixel
  • ispercentage
  • isem
  • isunit

Псевдонимы миксинов

Выпущено v3.5.0

Присвоение вызовов миксинов переменной

Миксины могут быть присвоены переменной для вызова как переменная или могут быть использованы для поиска в отображении.

#theme.dark.navbar {
  .colors(light) {
    primary: purple;
  }
  .colors(dark) {
    primary: black;
    secondary: grey;
  }
}

.navbar {
  @colors: #theme.dark.navbar.colors(dark);
  background: @colors[primary];
  border: 1px solid @colors[secondary];
}

Это выведет:

.navbar {
  background: black;
  border: 1px solid grey;
}

Вызовы переменных

Целые вызовы миксинов могут быть псевдонимизированы и вызваны как вызовы переменных. Как в:

#library() {
  .colors() {
    background: green;
  }
}
.box {
  @alias: #library.colors();
  @alias();
}

Вывод:

.box {
  background: green;
}

Обратите внимание, что, в отличие от миксинов, используемых в корне, вызовы миксинов, назначенные переменным и вызванные без аргументов, всегда требуют круглых скобок. Следующее неверно.

#library() {
  .colors() {
    background: green;
  }
}
.box {
  @alias: #library.colors;
  @alias();   // ERROR: Could not evaluate variable call @alias
}

Это потому, что неясно, назначена ли переменной список селекторов или вызов миксина. Например, в Less 3.5+ эта переменная может использоваться таким образом.

.box {
  @alias: #library.colors;
  @{alias} {
    a: b;
  }
}

Вышеприведенное выведет:

.box #library.colors {
  a: b;
}

CSS-защиты

«if» вокруг селекторов

Выпущено v1.5.0

Как и защиты миксинов, защиты также могут быть применены к CSS-селекторам, что является синтаксическим сахаром для объявления миксина и последующего немедленного вызова.

Например, до версии 1.5.0 вам пришлось бы сделать это:

.my-optional-style() when (@my-option = true) {
  button {
    color: white;
  }
}
.my-optional-style();

Теперь вы можете применить защиту непосредственно к стилю.

button when (@my-option = true) {
  color: white;
}

Вы также можете достичь оператора типа if путём комбинирования этого с функцией &, что позволяет группировать несколько защит.

& when (@my-option = true) {
  button {
    color: white;
  }
  a {
    color: blue;
  }
}

Обратите внимание, что вы также можете достичь аналогичного результата, используя фактическую функцию if() и вызов переменной. Например:

@dr: if(@my-option = true, {
  button {
    color: white;
  }
  a {
    color: blue;
  }
});
@dr();

Отделенные наборы правил

Присвоение набора правил переменной

Выпущено v1.7.0

Отделенный набор правил — это группа CSS-свойств, вложенных наборов правил, деклараций медиа или чего-либо ещё, хранящихся в переменной. Вы можете включить его в набор правил или другую структуру, и все его свойства будут скопированы туда. Вы также можете использовать его как аргумент миксина и передавать его как любую другую переменную.

Простой пример:

// declare detached ruleset
@detached-ruleset: { background: red; }; // semi-colon is optional in 3.5.0+

// use detached ruleset
.top {
    @detached-ruleset(); 
}

Компилируется в:

.top {
  background: red;
}

Круглые скобки после вызова отделённого набора правил обязательны (кроме случаев, когда за ними следует значение поиска). Вызов @detached-ruleset; не сработает.

Это полезно, когда вы хотите определить миксин, абстрагирующий либо обёртку куска кода в запрос медиа, либо имя класса браузера, не поддерживаемого браузером. Наборы правил могут быть переданы миксину, чтобы миксин мог обернуть содержимое, например:

.desktop-and-old-ie(@rules) {
  @media screen and (min-width: 1200px) { @rules(); }
  html.lt-ie9 &                         { @rules(); }
}

header {
  background-color: blue;

  .desktop-and-old-ie({
    background-color: red;
  });
}

Здесь миксин desktop-and-old-ie определяет запрос медиа и корневой класс, чтобы вы могли использовать миксин для обертывания куска кода. Это выведет

header {
  background-color: blue;
}
@media screen and (min-width: 1200px) {
  header {
    background-color: red;
  }
}
html.lt-ie9 header {
  background-color: red;
}

Теперь набор правил может быть присвоен переменной или передан в миксин и может содержать весь набор функций Less, например:

@my-ruleset: {
    .my-selector {
      background-color: black;
    }
  };

Вы даже можете использовать преимущества всплывания запросов медиа, например:

@my-ruleset: {
    .my-selector {
      @media tv {
        background-color: black;
      }
    }
  };
@media (orientation:portrait) {
    @my-ruleset();
}

который выведет

@media (orientation: portrait) and tv {
  .my-selector {
    background-color: black;
  }
}

Вызов отделённого набора правил разблокирует (возвращает) все его миксины в вызывающей области так же, как и вызовы миксинов. Однако он не возвращает переменные.

Возвращаемый миксин:

// detached ruleset with a mixin
@detached-ruleset: { 
    .mixin() {
        color: blue;
    }
};
// call detached ruleset
.caller {
    @detached-ruleset(); 
    .mixin();
}

Результат:

.caller {
  color: blue;
}

Приватные переменные:

@detached-ruleset: { 
    @color:blue; // this variable is private
};
.caller {
    color: @color; // syntax error
}

Области видимости

Отделенный набор правил может использовать все переменные и миксины, доступные в месте его определения и в месте его вызова. Иными словами, ему доступны и область определения, и область вызова. Если обе области содержат одну и ту же переменную или миксин, значение области объявления имеет приоритет.

Область объявления — это область, в которой определён тело отделённого набора правил. Копирование отделённого набора правил из одной переменной в другую не может изменить его область. Набор правил не получает доступа к новым областям просто благодаря ссылке на него.

Наконец, отделённый набор правил может получить доступ к области, разблокировавшись (импортировавшись) в неё.

Примечание: разблокировка переменных в область через вызываемый миксин устарела. Используйте доступ к свойствам/переменным.

Видимость области определения и вызова

Отделенный набор правил видит переменные и миксины вызывающего кода:

@detached-ruleset: {
  caller-variable: @caller-variable; // variable is undefined here
  .caller-mixin(); // mixin is undefined here
};

selector {
  // use detached ruleset
  @detached-ruleset(); 

  // define variable and mixin needed inside the detached ruleset
  @caller-variable: value;
  .caller-mixin() {
    variable: declaration;
  }
}

Компилируется в:

selector {
  caller-variable: value;
  variable: declaration;
}

Переменные и миксины, доступные из области определения, имеют преимущество перед теми, которые доступны в области вызова:

@variable: global;
@detached-ruleset: {
  // will use global variable, because it is accessible
  // from detached-ruleset definition
  variable: @variable; 
};

selector {
  @detached-ruleset();
  @variable: value; // variable defined in caller - will be ignored
}

Компилируется в:

selector {
  variable: global;
}

Ссылка не изменяет область отделённого набора правил

Набор правил не получает доступа к новым областям просто благодаря ссылке на него:

@detached-1: { scope-detached: @one @two; };
.one {
  @one: visible;
  .two {
    @detached-2: @detached-1; // copying/renaming ruleset 
    @two: visible; // ruleset can not see this variable
  }
}

.use-place {
  .one > .two(); 
  @detached-2();
}

выбрасывает ошибку:

ERROR 1:32 The variable "@one" was not declared.

Разблокировка изменит область видимости отсоединённого набора правил

Отсоединённый набор правил получает доступ, будучи разблокированным (импортированным) внутри области видимости:

#space {
  .importer-1() {
    @detached: { scope-detached: @variable; }; // define detached ruleset
  }
}

.importer-2() {
  @variable: value; // unlocked detached ruleset CAN see this variable
  #space > .importer-1(); // unlock/import detached ruleset
}

.use-place {
  .importer-2(); // unlock/import detached ruleset second time
   @detached();
}

компилируется в:

.use-place {
  scope-detached: value;
}

Доступ к свойствам/переменным

(Значения поиска)

Выпущено v3.5.0

Начиная с Less 3.5, вы можете использовать доступ к свойствам/переменным (также называемые "поисками") для выбора значения из переменных (отсоединённых) наборов правил.

@config: {
  option1: true;
  option2: false;
}

.mixin() when (@config[option1] = true) {
  selected: value;
}

.box {
  .mixin();
}

Вывод:

.box {
  selected: value;
}

Если возвращаемое значение поиска — это другой отсоединённый набор правил, вы можете использовать второй поиск для получения этого значения.

@config: {
  @colors: {
    primary: blue;
  }
}

.box {
  color: @config[@colors][primary];
}

Переменные переменных в поисках

Возвращаемое значение поиска само может быть переменной. То есть, вы можете написать:

@config: {
  @dark: {
    primary: darkblue;
  }
  @light: {
    primary: lightblue;
  }
}

.box {
  @lookup: dark;
  color: @config[@@lookup][primary];
}

Это выведет:

.box {
  color: darkblue;
}

@import Правила

Импортировать стили из других таблиц стилей

В стандартном CSS, @import правила @import должны предшествовать всем другим типам правил. Но Less не заботится о том, где вы размещаете @import инструкции.

Пример:

.foo {
  background: #900;
}
@import "this-is-valid.less";

Расширения файлов

@import инструкции могут обрабатываться Less по-разному в зависимости от расширения файла:

  • Если файл имеет .css расширение, он будет обрабатываться как CSS, и @import инструкция останется без изменений (см. вариант inline ниже).
  • Если у него любое другое расширение, он будет обрабатываться как Less и импортирован.
  • Если у него нет расширения, .less будет добавлено, и он будет включён как импортированный файл Less.

Примеры:

@import "foo";      // foo.less is imported
@import "foo.less"; // foo.less is imported
@import "foo.php";  // foo.php imported as a Less file
@import "foo.css";  // statement left in place, as-is

Следующие варианты могут быть использованы для переопределения этого поведения.

Параметры импорта

Less предлагает несколько расширений правила CSS @import CSS, чтобы предоставить больше гибкости в том, что можно делать с внешними файлами.

Синтаксис: @import (keyword) "filename";

Были реализованы следующие параметры импорта:

  • reference: использовать файл Less, но не выводить его
  • inline: включить исходный файл в выходные данные, но не обрабатывать его
  • less: обрабатывать файл как Less-файл, независимо от расширения файла
  • css: обрабатывать файл как CSS-файл, независимо от расширения файла
  • once: включить файл только один раз (это поведение по умолчанию)
  • multiple: включить файл несколько раз
  • optional: продолжать компиляцию, когда файл не найден

В @import допускается несколько ключевых слов; вы должны использовать запятые для разделения ключевых слов:

Пример: @import (optional, reference) "foo.less";

ссылка

Используйте @import (reference) для импорта внешних файлов, но не добавляйте импортированные стили в выходные данные компиляции, если они не сосланы.

Выпущено v1.5.0

Пример: @import (reference) "foo.less";

Представьте себе, что reference помечает каждое правило @import и селектор с флагом ссылки в импортированном файле, импортирует как обычно, но при генерации CSS, селекторы «reference» (а также любые медиа-запросы, содержащие только селекторы reference) не выводятся. reference стили не появятся в вашем сгенерированном CSS, если стили reference не используются в качестве миксов или расширений.

Кроме того, reference даёт разные результаты в зависимости от используемого метода (микс или расширение):

  • расширение: При расширении селектора только новый селектор отмечается как не сославшись, и он подтягивается в положение @import инструкции со ссылкой.
  • миксы: Когда reference стиль используется как неявный микс, его правила смешиваются, отмечаются как «не ссылка» и появляются в сосланом месте как обычно.

пример ссылки

Это позволяет подтянуть только конкретные, целевые стили из библиотеки, например, Bootstrap, сделав что-то вроде этого:

.navbar:extend(.navbar all) {}

И вы подтянете только .navbar связанные стили из Bootstrap.

inline

Используйте @import (inline) для включения внешних файлов, но не обрабатывайте их.

Выпущено v1.5.0

Пример: @import (inline) "not-less-compatible.css";

Вы используете это, когда CSS-файл может не быть совместим с Less; это потому, что хотя Less поддерживает большинство известных стандартов CSS, он не поддерживает комментарии в некоторых местах и не поддерживает все известные CSS-хаки без модификации CSS.

Поэтому вы можете использовать это для включения файла в выходные данные, чтобы весь CSS был в одном файле.

less

Используйте @import (less) для обработки импортированных файлов как Less, независимо от расширения файла.

Выпущено v1.4.0

Пример:

@import (less) "foo.css";

css

Используйте @import (css) для обработки импортированных файлов как обычного CSS, независимо от расширения файла. Это означает, что инструкция импорта останется такой, какая она есть.

Выпущено v1.4.0

Пример:

@import (css) "foo.less";

вывод

@import "foo.less";

once

Поведение по умолчанию @import инструкции. Это означает, что файл импортируется только один раз, а последующие инструкции импорта для этого файла будут игнорироваться.

Выпущено v1.4.0

Это поведение по умолчанию @import инструкций.

Пример:

@import (once) "foo.less";
@import (once) "foo.less"; // this statement will be ignored

multiple

Используйте @import (multiple) для разрешения импорта нескольких файлов с тем же именем. Это поведение, противоположное once.

Выпущено v1.4.0

Пример:

// file: foo.less
.a {
  color: green;
}
// file: main.less
@import (multiple) "foo.less";
@import (multiple) "foo.less";

Вывод

.a {
  color: green;
}
.a {
  color: green;
}

optional

Используйте @import (optional) для разрешения импорта файла только в том случае, если он существует. Без ключевого слова optional Less выбрасывает FileError и останавливает компиляцию при импорте файла, который не может быть найден.

Выпущено v2.3.0

@plugin Правила

Выпущено v2.5.0

Импортировать JavaScript плагины для добавления функций и возможностей Less.js

Написание вашего первого плагина

Использование правила @plugin аналогично использованию @import для ваших .less файлов.

@plugin "my-plugin";  // automatically appends .js if no extension

Поскольку плагины Less оцениваются в области видимости Less, определение плагина может быть достаточно простым.

registerPlugin({
    install: function(less, pluginManager, functions) {
        functions.add('pi', function() {
            return Math.PI;
        });
    }
})

или вы можете использовать module.exports (адаптировано для работы в браузере и Node.js).

module.exports = {
    install: function(less, pluginManager, functions) {
        functions.add('pi', function() {
            return Math.PI;
        });
    }
};

Обратите внимание, что другие соглашения Node.js CommonJS, такие как require() недоступны в браузере. Помните об этом при написании кроссплатформенных плагинов.

Что вы можете сделать с плагином? Много, но давайте начнём с основ. Мы сосредоточимся на том, что вы можете поместить внутри функции install. Предположим, вы напишете это:

// my-plugin.js
install: function(less, pluginManager, functions) {
    functions.add('pi', function() {
        return Math.PI;
    });
}
// etc

Поздравляем! Вы написали плагин Less!

Если вы использовали бы это в своём файле стилей:

@plugin "my-plugin";
.show-me-pi {
  value: pi();
}

Вы получите:

.show-me-pi {
  value: 3.141592653589793;
}

Однако, вам нужно вернуть правильный узел Less, если вы хотите, например, умножить это на другие значения или выполнить другие операции Less. Иначе вывод в вашем файле стилей — это обычный текст (что может подойти для ваших целей).

Значит, это более правильно:

functions.add('pi', function() {
    return new tree.Dimension(Math.PI);
});

Примечание: размер — это число с или без единицы измерения, например, «10px», которое будет less.Dimension(10, "px"). Список единиц измерения см. в API Less.

Теперь вы можете использовать свою функцию в операциях.

@plugin "my-plugin";
.show-me-pi {
  value: pi() * 2;
}

Вы могли заметить, что доступны глобальные переменные для вашего файла плагина, а именно регистр функций (объект functions) и объект less. Они доступны для удобства.

Область видимости плагина

Функции, добавленные правилом @plugin, подчиняются правилам области видимости Less. Это отлично подходит для авторов библиотек Less, которые хотят добавлять функциональность, не вводя конфликтов имён.

Например, у вас есть 2 плагина из двух сторонних библиотек, у которых обеих есть функция с именем «foo».

// lib1.js
// ...
    functions.add('foo', function() {
        return "foo";
    });
// ...

// lib2.js
// ...
    functions.add('foo', function() {
        return "bar";
    });
// ...

Это нормально! Вы можете выбрать, функция какой библиотеки создаёт тот или иной вывод.

.el-1 {
    @plugin "lib1";
    value: foo();
}
.el-2 {
    @plugin "lib2";
    value: foo();
}

Это даст:

.el-1 {
    value: foo;
}
.el-2 {
    value: bar;
}

Для авторов плагинов, которые разделяют свои плагины, это означает, что вы также можете эффективно создавать закрытые функции, помещая их в определённую область видимости. То есть, это приведёт к ошибке:

.el {
    @plugin "lib1";
}
@value: foo();

Начиная с Less 3.0, функции могут возвращать любой тип узла и вызываться на любом уровне.

Значит, это выбросило бы ошибку в 2.x, так как функции должны были быть частью значения свойства или присваивания переменной:

.block {
    color: blue;
    my-function-rules();
}

В 3.x это больше не так, и функции могут возвращать правила @import, наборы правил, любые другие узлы Less, строки и числа (последние два преобразуются в анонимные узлы).

Функции null

Иногда вам может понадобиться вызвать функцию, но вы не хотите ничего выводить (например, для хранения значения для последующего использования). В этом случае вам нужно просто вернуть false из функции.

var collection = [];

functions.add('store', function(val) {
    collection.push(val);  // imma store this for later
    return false;
});
@plugin "collections";
@var: 32;
store(@var);

Позже вы могли бы сделать что-то вроде:

functions.add('retrieve', function(val) {
    return new tree.Value(collection);
});
.get-my-values {
    @plugin "collections";
    values: retrieve();   
}

Объект плагина Less.js

Плагин Less.js должен экспортировать объект, который имеет одну или несколько из этих свойств.

{
    /* Called immediately after the plugin is 
     * first imported, only once. */
    install: function(less, pluginManager, functions) { },

    /* Called for each instance of your @plugin. */
    use: function(context) { },

    /* Called for each instance of your @plugin, 
     * when rules are being evaluated.
     * It's just later in the evaluation lifecycle */
    eval: function(context) { },

    /* Passes an arbitrary string to your plugin 
     * e.g. @plugin (args) "file";
     * This string is not parsed for you, 
     * so it can contain (almost) anything */
    setOptions: function(argumentString) { },

    /* Set a minimum Less compatibility string
     * You can also use an array, as in [3, 0] */
    minVersion: ['3.0'],

    /* Used for lessc only, to explain 
     * options in a Terminal */
    printUsage: function() { },

}

Экземпляр PluginManager для функции install() предоставляет методы для добавления посетителей, менеджеров файлов и постпроцессоров.

Вот некоторые примеры репозиториев, демонстрирующие различные типы плагинов.

  • постпроцессор: https://github.com/less/less-plugin-clean-css
  • посетитель: https://github.com/less/less-plugin-inline-urls
  • менеджер файлов: https://github.com/less/less-plugin-npm-import

Загруженные по умолчанию плагины

Хотя вызов @plugin хорошо работает в большинстве случаев, есть ситуации, когда вам может потребоваться загрузить плагин до начала парсинга.

См.: Загруженные по умолчанию плагины в разделе "Использование Less.js", чтобы узнать, как это сделать.

Карты (НОВОЕ!)

Выпущено v3.5.0

Используйте правила и миксины как карты значений

Комбинируя именование с синтаксисом поиска [], вы можете преобразовать свои правила/миксины в карты.

@sizes: {
  mobile: 320px;
  tablet: 768px;
  desktop: 1024px;
}

.navbar {
  display: block;

  @media (min-width: @sizes[tablet]) {
    display: inline-block;
  }
}

Выходные данные:

.navbar {
  display: block;
}
@media (min-width: 768px) {
  .navbar {
    display: inline-block;
  }
}

Миксины немного более универсальны в качестве карт из-за именования и возможности перегрузки миксинов.

#library() {
  .colors() {
    primary: green;
    secondary: blue;
  }
}

#library() {
  .colors() { primary: grey; }
}

.button {
  color: #library.colors[primary];
  border-color: #library.colors[secondary];
}

Выходные данные:

.button {
  color: grey;
  border-color: blue;
}

Вы также можете упростить это, используя алиасы миксинов.

.button {
  @colors: #library.colors();
  color: @colors[primary];
  border-color: @colors[secondary];
}

Обратите внимание, что если значение поиска возвращает другое правило, вы можете добавить второй поиск [], как в:

@config: {
  @options: {
    library-on: true
  }
}

& when (@config[@options][library-on] = true) {
  .produce-ruleset {
    prop: val;
  }
}

Таким образом, правила и вызовы переменных могут эмулировать тип "именования", аналогично миксинам.

Что касается того, использовать ли миксины или правила, назначенные переменным, в качестве карт, решение за вами. Вы можете заменить целые карты, повторно объявив переменную, назначенную правилу. Или вы можете "объединить" отдельные пары ключ/значение, в этом случае миксины в качестве карт могут быть более подходящими.

Использование переменных переменных в поисках

Важно заметить, что значение в [@lookup] — это имя ключа (переменной) @lookup, и оно не оценивается как переменная. Если вы хотите, чтобы само имя ключа было переменным, вы можете использовать синтаксис @@variable.

Например:

.foods() {
  @dessert: ice cream;
}

@key-to-lookup: dessert;

.lunch {
  treat: .foods[@@key-to-lookup];
}

Это выведет:

.lunch {
  treat: ice cream;
}

© 2009–2020 The Core Less Team
Licensed under the Creative Commons Attribution License 3.0.
http://lesscss.org/features

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API