概述

编辑“概述”的markdown源代码

LESS 语言功能的深入指南。请参阅 概述 以快速了解 Less。

有关安装和设置 Less 环境的深入指南以及 Less 开发文档,请参阅:使用 Less.js


变量

编辑“变量”的markdown源代码

在单个位置控制常用的值。

概述

在样式表中看到几十次(如果不是几百次)重复相同的值的情况并不少见

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 为深红色。


父选择器

编辑“parent-selectors”的 markdown 源

使用 & 引用父选择器

& 运算符表示 嵌套规则 的父选择器,最常见于将修改类或伪类应用于现有选择器

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 & 将在其父 .header .menu 之前添加 .no-borderradius,以在输出中形成 .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;
}

@import At 规则

编辑“导入”的 Markdown 源

从其他样式表导入样式

在标准 CSS 中,@import at 规则必须位于所有其他类型规则之前。但 Less 不关心你将 @import 语句放在哪里。

示例

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

文件扩展名

@import 语句可能会根据文件扩展名以不同的方式被 Less 处理

  • 如果文件具有 .css 扩展名,它将被视为 CSS,并且 @import 语句保持原样(请参阅下面的 内联选项)。
  • 如果它具有任何其他扩展名,它将被视为 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 at 规则提供了几个扩展,以便更灵活地处理外部文件。

语法:@import (关键字) "文件名";

已实现以下导入选项

  • 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 标记导入文件中每个 at 规则和选择器带有 reference 标记,按正常方式导入,但在生成 CSS 时,不会输出“reference”选择器(以及仅包含 reference 选择器的任何媒体查询)。除非 reference 样式用作 mixins扩展,否则 reference 样式不会显示在生成的 CSS 中。

此外,reference 根据使用的方法(mixin 或扩展)产生不同的结果

  • 扩展:当一个选择器被扩展时,只有新选择器被标记为 未引用,并且它在 reference @import 语句的位置被拉入。
  • mixins:当一个 reference 样式用作 隐式 mixin 时,它的规则被混合,标记为“未引用”,并按正常方式出现在引用位置。

reference 示例

这允许您仅从库中提取特定的目标样式,例如 Bootstrap,方法如下

.navbar:extend(.navbar all) {}

您将仅从 Bootstrap 中提取 .navbar 相关的样式。

inline

使用 @import (inline) 包含外部文件,但不处理它们。

发布 v1.5.0

示例:@import (inline) "not-less-compatible.css";

当 CSS 文件可能与 Less 不兼容时,您将使用此方法;这是因为尽管 Less 支持大多数已知的标准 CSS,但它不支持某些位置的注释,并且不支持在不修改 CSS 的情况下支持所有已知的 CSS hack。

因此,您可以使用此方法将文件包含在输出中,以便所有 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


Extend

编辑 "extend" 的 markdown 源代码

Extend 是一个 Less 伪类,它将它所在的 selector 与匹配它所引用的 selector 合并。

发布 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:visitedlink:visited:hover 匹配同一组元素,但扩展将它们视为不同

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

输出

link:hover:visited {
  color: blue;
}

nth 表达式

nth 表达式形式很重要。nth 表达式 1n+3n+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 关键字时,它会告诉 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 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 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 */
}

扩展用例

经典用例

经典用例是避免添加基类。例如,如果您有

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

并且您想要一个覆盖背景色的动物子类型,那么您有两个选择,首先更改您的 HTML

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

或者简化 HTML 并使用 less 中的扩展。例如

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

减小 CSS 大小

混合会将所有属性复制到一个选择器中,这可能导致不必要的重复。因此,您可以使用扩展而不是混合来将选择器移动到您希望使用的属性,从而减少生成的 CSS。

示例 - 使用混合

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

示例(使用扩展)

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

组合样式 / 更高级的混合

另一个用例是作为混合的替代品 - 因为混合只能与简单选择器一起使用,如果您有两个不同的 HTML 块,但需要对两者应用相同的样式,则可以使用扩展来关联两个区域。

示例

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

合并属性

编辑“合并”的 markdown 源

合并属性

merge 功能允许将来自多个属性的值聚合到单个属性下的逗号或空格分隔列表中。merge 对于背景和变换等属性很有用。

逗号

使用逗号追加属性值

发布 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”的 markdown 源

从现有样式中“混合”属性

您可以混合类选择器和 id 选择器,例如

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

结果为

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

从历史上看,混合调用中的括号是可选的,但可选括号已被弃用,并且在未来的版本中将是必需的。

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

带括号的混合

如果您想创建一个混合,但不想让该混合出现在您的 CSS 输出中,请在混合定义后加上括号。

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

输出

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

混合中的选择器

混合不仅可以包含属性,还可以包含选择器。

例如

.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 语法允许在命名空间和混合之间使用 > 和空格。此语法已弃用,可能会被移除。目前,它们的作用相同。

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

像这样对您的混合进行命名空间化可以减少与其他库混合或用户混合的冲突,但也可以成为“组织”混合组的一种方式。

示例

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

受保护的命名空间

如果一个命名空间有一个保护,那么它定义的混合只有在保护条件返回 true 时才会使用。命名空间保护的评估与混合保护的评估完全相同,因此以下两个混合的工作方式相同

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

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

default 函数被认为对所有嵌套命名空间和混合具有相同的值。以下混合永远不会被评估;它的一个保护必定为假

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

!important 关键字

在 mixin 调用后使用 !important 关键字,将所有继承的属性标记为 !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;
}

参数化 Mixin

编辑 "mixins-parametric" 的 markdown 源代码

如何向 mixin 传递参数

Mixin 还可以接受参数,这些参数是在 mixin 混合时传递给选择器块的变量。

例如

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

下面是如何将其混合到各种规则集中

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

参数化 Mixin 也可以为其参数设置默认值

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

现在我们可以这样调用它

#header {
  .border-radius();
}

它将包含一个 5px 的边框半径。

你还可以使用不带参数的参数化 Mixin。如果你想在 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;
}

参数分隔符

参数目前使用分号逗号分隔。

最初,参数仅用逗号分隔,但后来添加了分号,以支持将逗号分隔的列表值传递给单个参数。

注意:从 Less 4.0 开始,你可以使用括号转义 [~()] 包装列表值,例如 .name(@param1: ~(red, blue))。这类似于引号转义语法:~"quote"。这可能会使你的代码库中不再需要分号分隔符。

示例

  • 两个参数,每个参数都包含逗号分隔的列表:.name(1, 2, 3; something, else)
  • 三个参数,每个参数都包含一个数字:.name(1, 2, 3)
  • 使用一个虚拟分号创建一个 mixin 调用,其中一个参数包含一个逗号分隔的 css 列表:.name(1, 2, 3;)注意:如果尾随分号看起来很奇怪,你可能更喜欢:.name(~(1, 2, 3))
  • 编写逗号分隔默认值的方法
    • @param-values: red, blue; .name(@param1: @param-values).
    • .name(@param1: red, blue;)
    • .name(@param1: ~(red, blue))

重载 Mixin

使用具有相同名称和参数数量的多个混合是合法的。Less 将使用所有适用的属性。如果你使用具有一个参数的混合,例如 .mixin(green);,那么将使用具有一个强制参数的所有混合的属性

.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(@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 在混合中具有特殊含义,它包含在调用混合时传递的所有参数。如果你不想处理单个参数,这将很有用

.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(...) {        // 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(@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,则结果将是较暗的颜色。

以下是发生的情况

  • 第一个混合定义不匹配,因为它期望 dark 作为第一个参数。
  • 第二个混合定义匹配,因为它期望 light
  • 第三个混合定义匹配,因为它期望任何值。

仅使用匹配的混合定义。变量匹配并绑定到任何值。除变量之外的任何其他内容仅与等于其自身的值匹配。

我们还可以匹配元数,这是一个示例

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

现在,如果我们使用单个参数调用 .mixin,我们将获得第一个定义的输出,但如果我们使用两个参数调用它,我们将获得第二个定义,即 @a 渐变为 @b


将 Mixin 用作函数

编辑 "mixins-as-functions" 的 markdown 源代码

从 mixin 调用中选择属性和变量

属性/值访问器

在 Less 3.5 中发布 v3.5.0

从 Less 3.5 开始,你可以使用属性/变量访问器从已评估 mixin 的规则中选择一个值。这让你可以使用类似于函数的 mixin。

示例

.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 值

如果你有多个匹配的 mixin,所有规则都将被评估并合并,并返回具有该标识符的最后一个匹配值。这类似于 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 或规则集调用后写 []所有值都将层叠,并且将选择最后声明的值。

这意味着:上面的示例中的平均 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;
}

对于别名为 mixin 调用的规则集或变量,相同的层叠行为也是正确的。

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

输出

.box {
  my-value: foo;
}

将 Mixin 和变量解锁到调用方作用域

已弃用 - 使用属性/值访问器

在 Mixin 中定义的变量和 Mixin 可见,且可以在调用方的作用域中使用。只有一个例外:如果调用方包含具有相同名称的变量(包括由另一个 Mixin 调用定义的变量),则不会复制该变量。仅保护调用方局部作用域中存在的变量。从父作用域继承的变量会被覆盖。

注意:此行为已弃用,将来,变量和 Mixin 将不会以这种方式合并到调用方作用域中。

示例

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

最后,在 Mixin 中定义的 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;
}

递归 Mixin

编辑“mixin-loops”的 Markdown 源代码

创建循环

在 Less 中,Mixin 可以调用自身。此类递归 Mixin 与 保护表达式模式匹配结合使用,可用于创建各种迭代/循环结构。

示例

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

Mixin 保护

编辑“mixin-guards”的 Markdown 源代码

当您想匹配表达式(而不是简单值或元数)时,保护非常有用。如果您熟悉函数式编程,您可能已经遇到过它们。

为了尽可能贴近 CSS 的声明式本质,Less 选择通过受保护的 Mixin而不是 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) { ... }

您可以通过用逗号 , 分隔守卫来模拟 or 运算符。如果任何守卫计算结果为真,则认为匹配

.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

混入别名

编辑 "mixins-aliasing" 的 markdown 源代码

在 Less 3.5 中发布 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;
}

分离规则集

编辑 "detached-rulesets" 的 markdown 源代码

将规则集分配给变量

发布 v1.7.0

分离规则集是存储在变量中的 css 属性、嵌套规则集、媒体声明或其他任何内容的组。你可以将其包含到规则集或其他结构中,并且其所有属性都将被复制到那里。你还可以将其用作 mixin 参数,并像其他任何变量一样传递它。

简单示例

// 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; 将不起作用。

当你想定义一个 mixin 来抽象出将一段代码包装在媒体查询或不受支持的浏览器类名中时,它很有用。规则集可以传递给 mixin,以便 mixin 可以包装内容,例如

.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 mixin 定义了媒体查询和根类名,以便你可以使用 mixin 来包装一段代码。这将输出

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

现在可以将规则集分配给变量或传递给 mixin,并且可以包含 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;
  }
}

分离规则集调用会以与 mixin 调用相同的方式解锁(返回)其所有 mixin 到调用方。但是,它不会返回变量。

返回的 mixin

// 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
}

作用域

分离规则集可以使用在定义调用它的位置可访问的所有变量和 mixin。换句话说,它可以使用定义和调用方作用域。如果两个作用域都包含相同的变量或 mixin,则声明作用域值优先。

声明作用域是分离规则集主体被定义的作用域。将分离规则集从一个变量复制到另一个变量不会修改其作用域。规则集不会仅仅通过在那里被引用就获得对新作用域的访问权限。

最后,分离规则集可以通过解锁(导入)到作用域中来获得对作用域的访问权限。

注意:通过调用的 mixin 将变量解锁到作用域中已被弃用。使用 属性/变量访问器

定义和调用方作用域可见性

独立规则集会看到调用者的变量和混合

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

属性/变量访问器

(查找值)

在 Less 3.5 中发布 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;
}

映射

编辑“映射”的 markdown 源

在 Less 3.5 中发布 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;
}

范围

编辑“范围”的 markdown 源

Less 的一些其他范围功能

混合范围功能

直观地说,混合可以访问定义范围。

#ns {
  @a: one;
  .mixin-1() {
    prop: @a;
  }
}
.rule {
  #ns.mixin-1();
}

/* OUTPUTS:
.rule {
  prop: one;
}
*/

已弃用的混合范围功能

这是一些可能在未来版本中删除的混合范围功能的列表。

#1.(已弃用)混合可以访问调用者范围。

#ns {
  .mixin-1() {
    prop: @a;
  }
}
.rule {
  @a: one;
  #ns.mixin-1();
}
/* OUTPUTS:
.rule {
  prop: one;
}
*/

这是违反直觉的,因为

  1. 在大多数其他语言中都不常见。
  2. 从定义中无法立即看出混合将生成什么输出。

首选方法:传递您希望对混合可见的变量。

#ns {
  .mixin-1(@a) {
    prop: @a;
  }
}
.rule {
  #ns.mixin-1(@a: one);
}

#2.(已弃用)调用者范围可以访问混合中的变量

Mixin 将把它们自己的变量推送到调用者作用域,但仅在变量未在本地定义时才这样做。

#ns {
  .mixin-1() {
    @a: one;
    @b: two;
  }
}
.rule {
  @b: three;
  #ns.mixin-1();
  prop-1: @a;
  prop-2: @b;
}
/* OUTPUTS:
.rule {
  prop-1: one;
  prop-2: three;
}
*/

这是违反直觉的,因为

  1. 调用者作用域中较高的变量可以被覆盖。
  2. 它也不是一种典型的语言行为。
  3. 它与分离规则集的行为不同。

此外,通过引入映射,你可以直接检索变量值(和 mixin)。

首选方法:

#ns {
  .mixin-1() {
    @a: one;
    @b: two;
  }
}
.rule {
  @returns: #ns.mixin-1();
  prop-1: @returns[@a];
  prop-2: @returns[@b];
}
/* OUTPUTS:
.rule {
  prop-1: one;
  prop-2: two;
}
*/

#3.(已弃用)调用者作用域可以访问 mixin 中的 mixin

与已弃用的变量行为类似,mixin 也被推送到调用者作用域。但是,与变量不同,与合并作用域 mixin 同名的 mixin 会被合并。

#ns {
  .mixin-1() {
    prop-1: one;
    prop-2: two;
  }
}
.rule {
  #ns();
  .mixin-1();
  .mixin-1() {
    prop-3: three;
  }
}
/* OUTPUT:
.rule {
  prop-1: one;
  prop-2: two;
  prop-3: three;
}
*/

首选方法:直接调用 mixin。

#ns {
  .mixin-1() {
    prop-1: one;
    prop-2: two;
  }
}
.rule {
  .mixin-1() {
    prop-3: three;
  }
  #ns.mixin-1();
  .mixin-1();
}
/* OUTPUT:
.rule {
  prop-1: one;
  prop-2: two;
  prop-3: three;
}
*/

提示和技巧

鸣谢:less/less.js/issues/1472

以下是一个技巧,用于定义变量并将其保留在某个私有作用域中,防止它们泄漏到全局空间。

& {
  // Vars
  @height: 100px;
  @width: 20px;
  // Don't define any prop:value on this scope (as doing so will generate (wrong) output).

  .test {
    height: @height;
    width: @width;
  }
}

.rest {
  height: @height; // Name error: variable @height is undefined
}

此处,@height@width 仅针对 & { ... } 创建的作用域定义。你还可以将作用域嵌套在规则中

.some-module {
  @height: 200px;
  @width: 200px;
  text-align: left;
  line-height: @height; // 200px

  & {
    // Override original values
    @height: 100px;
    @width: auto;

    .some-module__element {
      height: @height; // 100px
      width: @width; // 200px
    }

    .some-module__element .text {
      line-height: (@height / 2); // 50px
    }
  }

  & {
    // Override original values
    @height: 50px;

    .some-module__another-element {
      height: @height; // 50px
      width: @width; // 200px
    }

    .some-module__another-element .text {
      line-height: (@height / 2); // 25px
    }
  }
}

CSS 保护

编辑“css-guards”的 markdown 源代码

选择器周围的“if”

发布 v1.5.0

与 Mixin 保护类似,保护也可以应用于 css 选择器,这是一种语法糖,用于声明 mixin 然后立即调用它。

例如,在 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();

@plugin At 规则

编辑“plugins”的 markdown 源代码

发布 v2.5.0

导入 JavaScript 插件以添加 Less.js 函数和特性

编写你的第一个插件

使用 @plugin at-rule 类似于为 .less 文件使用 @import

@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")。有关单位列表,请参阅 Less API

现在你可以在操作中使用你的函数。

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

你可能已经注意到,你的插件文件有一些可用的全局变量,即函数注册表(functions 对象)和 less 对象。这些是为了方便而存在的。

插件范围

通过 @plugin at-rule 添加的函数遵循 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 中,不再是这样,函数可以返回 At-Rules、Rulesets、任何其他 Less 节点、字符串和数字(后两者将转换为 Anonymous 节点)。

空函数

有时,你可能希望调用一个函数,但你不想输出任何内容(例如存储一个值以供以后使用)。在这种情况下,你只需要从函数返回 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() { },

}

install() 函数的 PluginManager 实例提供用于添加访问器、文件管理器和后置处理器的函数。

以下是一些展示不同插件类型的示例仓库。

预加载插件

虽然 @plugin 调用适用于大多数场景,但在某些情况下,你可能希望在解析开始之前加载插件。

请参阅“使用 Less.js”部分中的 预加载插件,了解如何执行此操作。