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;
}
Расширение
Расширение — это псевдокласс 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;
}
Вы можете представить этот режим работы как неразрушающий поиск и замену.
Интерполяция селектора с расширением
Расширение не может сопоставлять селекторы с переменными. Если селектор содержит переменную, расширение её проигнорирует.
Однако расширение может быть прикреплено к интерполированному селектору.
Селектор с переменной не будет сопоставлен:
@variable: .bucket;
@{variable} { // interpolated selector
color: blue;
}
.some-class:extend(.bucket) {} // does nothing, no match is found
и расширение с переменной в целевом селекторе ничего не сопоставляет:
.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;
}
Область видимости / Расширение внутри @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;
}
}
Селектор расширения верхнего уровня соответствует всем, включая селекторы внутри вложенных 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, но вам необходимо применить те же стили к обоим, вы можете использовать extend для связывания двух областей.
Пример:
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;
}
Пространства имён
Если вы хотите смешать свойства внутри более сложного селектора, вы можете объединить несколько id или классов.
#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();
}
И он включит радиус границы 5 пикселей.
Вы также можете использовать параметрические 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;
}
Mixins с несколькими параметрами
Параметры разделяются либо точкой с запятой, либо запятой. Рекомендуется использовать точку с запятой. Символ запятой имеет двойное значение: он может интерпретироваться либо как разделитель параметров mixin, либо как разделитель списков CSS.
Использование запятой в качестве разделителя параметров mixin делает невозможным создание списков, разделённых запятыми, в качестве аргумента. С другой стороны, если компилятор видит хотя бы одну точку с запятой внутри вызова или объявления mixin, он предполагает, что аргументы разделены точками с запятой, а все запятые относятся к спискам CSS:
- два аргумента, и каждый содержит список, разделённый запятыми:
.name(1, 2, 3; something, else), - три аргумента, и каждый содержит одно число:
.name(1, 2, 3), - использовать фиктивную точку с запятой для создания вызова mixin с одним аргументом, содержащим список CSS, разделённый запятыми:
.name(1, 2, 3;), - значение по умолчанию, разделённое запятыми:
.name(@param1: red, blue;).
Допустимо определять несколько 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 совпало, потому что оно ожидало любое значение.
Использовались только те определения mixin, которые совпали. Переменные совпадают и привязываются к любому значению. Всё, что не является переменной, совпадает только со значением, равным ей самому.
Мы также можем сопоставлять по арности, вот пример:
.mixin(@a) {
color: @a;
}
.mixin(@a; @b) {
color: fade(@a; @b);
}
Теперь, если мы вызовем .mixin с одним аргументом, мы получим вывод первого определения, но если мы вызовем его с двумя аргументами, мы получим второе определение, а именно @a с потускнением до @b.
Использование Mixins как функций
Выбор свойств и переменных из вызовов mixin
Доступ к свойствам/значениям
Выпущено v3.5.0
Начиная с Less 3.5, вы можете использовать доступ к свойствам/переменным для выбора значения из правил вычисленного mixin. Это позволяет использовать mixins подобно функциям.
Пример:
.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;
}
Переопределение значений mixin
Если у вас есть несколько соответствующих mixins, все правила оцениваются и объединяются, и возвращается последнее соответствующее значение с этим идентификатором. Это аналогично каскаду в CSS, и это позволяет вам «переопределять» значения mixin.
// 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] и вместо этого напишете [] после вызова mixin или набора правил, все значения будут каскадированы, и последнее объявленное значение будет выбрано.
Это означает, что миксин усреднения из предыдущего примера можно записать как:
.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) { ... }
Вы можете эмулировать оператор или, разделяя защиты запятой ,. Если какое-либо из защит принимает значение true, это считается совпадением:
.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)) { ... }
Вот основные функции проверки типа:
iscolorisnumberisstringiskeywordisurl
Если вы хотите проверить, является ли значение числом с определённой единицей измерения, помимо того, что оно является числом, вы можете использовать одну из:
ispixelispercentageisemisunit
Сопоставление миксинов
Выпущено 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() {
.rules() {
background: green;
}
}
.box {
@alias: #library.rules();
@alias();
}
Вывод:
.box {
background: green;
}
Обратите внимание, что в отличие от миксинов, используемых в корне, вызовы миксинов, присвоенные переменным и вызываемые без аргументов, всегда требуют скобок. Следующее недействительно.
#library() {
.rules() {
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 должны предшествовать всем другим типам правил. Но 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 , чтобы предоставить большую гибкость при работе с внешними файлами.
Синтаксис: @import (keyword) "filename";
Следующие опции импорта реализованы:
-
reference: использовать файл Less, но не выводить его -
inline: включать исходный файл в выходные данные, но не обрабатывать его -
less: обрабатывать файл как файл Less, независимо от расширения файла -
css: обрабатывать файл как CSS-файл, независимо от расширения файла -
once: включать файл только один раз (это стандартное поведение) -
multiple: включать файл многократно -
optional: продолжать компиляцию, когда файл не найден
Разрешается использование нескольких ключевых слов в @import , разделенных запятыми:
Пример: @import (optional, reference) "foo.less";
reference
Используйте @import (reference) для импорта внешних файлов, но без добавления импортированных стилей в скомпилированный результат, если они не ссылаются.
Выпущено v1.5.0
Пример: @import (reference) "foo.less";
Представьте, что reference помечает каждое правило и селектор в импортированном файле флагом ссылки, импортирует как обычно, но при генерации CSS, селекторы "reference" (а также любые медиазапросы, содержащие только селекторы reference) не выводятся. reference стили не будут отображаться в сгенерированном CSS, пока стили reference не будут использованы как миксины или расширения.
Кроме того, reference даёт разные результаты в зависимости от используемого метода (миксин или расширение):
-
расширение: Когда селектор расширяется, только новый селектор помечается как не сославшись, и он включается в позицию ссылочного
@importоператора. -
миксины: Когда
referenceстиль используется как явный миксин, его правила включаются, помечаются как "не ссылка", и появляются в ссылаемом месте, как обычно.
пример 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 это больше не так, и функции могут возвращать правила, наборы правил, любой другой узел 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