概述

Edit the markdown source for "overview"

Less 语言特性的深入指南。请参阅概述以快速了解 Less。

关于安装和设置 Less 环境以及 Less 开发文档的详细指南,请参见:使用 Less.js


变量

Edit the markdown source for "variables"

在单一位置控制常用值。

概述

在样式表中看到相同的值重复数十甚至数百次并不罕见:

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

变量通过让你能够从单一位置控制这些值,使你的代码更易于维护:

// 变量
@link-color:        #428bca; // 海蓝色
@link-color-hover:  darken(@link-color, 10%);

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

变量插值

上面的示例侧重于使用变量控制 CSS 规则中的 _值_,但它们也可以在其他地方使用,如选择器名称、属性名称、URL 和 @import 语句。

选择器

v1.4.0

// 变量
@my-selector: banner;

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

编译为:

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

URLs

// 变量
@images: "../img";

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

导入语句

v1.4.0

语法:@import "@{themes}/tidal-wave.less";

注意在 v2.0.0 之前,只考虑在根或当前作用域中声明的变量,并且只考虑当前文件和调用文件来查找变量。

示例:

// 变量
@themes: "../../src/themes";

// 使用
@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);  // 颜色是黑色
  --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;  
} 

Compiles to:

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

Default Variables

We sometimes get requests for default variables - an ability to set a variable only if it is not already set. This feature is not required because you can easily override a variable by putting the definition afterwards.

For instance:

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

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

This works fine because of Lazy Loading - @base-color is overridden and @dark-color is a dark red.


父选择器

Edit the markdown source for "parent-selectors"

使用 & 引用父选择器

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

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

@import 规则

Edit the markdown source for "imports"

从其他样式表导入样式

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

示例:

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

文件扩展名

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

  • 如果文件有 .css 扩展名,它将被视为 CSS,并且 @import 语句将保持原样(请参见下面的 内联选项)。
  • 如果是任何其他扩展名,它将被视为 Less 并导入。
  • 如果没有扩展名,将追加 .less 并作为导入的 Less 文件包含。

示例:

@import "foo";      // 导入 foo.less
@import "foo.less"; // 导入 foo.less
@import "foo.php";  // 作为 Less 文件导入 foo.php
@import "foo.css";  // 语句原样保留

以下选项可用于覆盖此行为。

导入选项

Less 对 CSS @import 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-规则和选择器为引用标志,正常导入,但在生成 CSS 时,"引用"选择器(以及仅包含引用选择器的任何媒体查询)不会输出。除非引用样式被用作混合扩展,否则不会出现在生成的 CSS 中。

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

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

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 黑客技巧。

因此,你可以使用它在输出中包含文件,以便所有 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"; // 这个语句将被忽略

multiple

使用 @import (multiple) 允许导入多个同名文件。这是 once 的相反行为。

发布于 v1.4.0

示例:

// 文件:foo.less
.a {
  color: green;
}
// 文件: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


扩展

Edit the markdown source for "extend"

Extend 是一个 Less 伪类,它将选择器与匹配其引用的选择器合并。

发布于 v1.4.0

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

在上面的规则集中,:extend 选择器将"扩展选择器"(nav ul)应用到 .inline 类上 无论 .inline 类出现在哪里。声明块将保持原样,但不引用扩展(因为扩展不是 CSS)。

所以以下代码:

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

输出

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

注意 nav ul:extend(.inline) 选择器是如何输出为 nav ul 的 - 扩展在输出前被移除,选择器块保持原样。如果该块中没有属性,则从输出中删除(但扩展仍可能影响其他选择器)。

Extend 语法

扩展可以附加到选择器上,也可以放置在规则集中。它看起来像一个带有选择器参数的伪类,后面可选跟随 all 关键字:

示例:

.a:extend(.b) {}

// 上面的块与下面的块做的事情相同
.a {
  &:extend(.b);
}
.c:extend(.d all) {
  // 扩展 ".d" 的所有实例,例如 ".x.d" 或 ".d.x"
}
.c:extend(.d) {
  // 仅扩展将被输出为 ".d" 的实例
}

它可以包含一个或多个要扩展的类,用逗号分隔。

示例:

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

// 上面和下面做的事情相同
.e:extend(.f, .g) {}

附加到选择器的 Extend

附加到选择器的 Extend 看起来像一个带有选择器作为参数的普通伪类。一个选择器可以包含多个扩展子句,但所有扩展必须在选择器末尾。

  • 选择器后的扩展: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) {
  // 主体
}

规则集内部的 Extend

可以使用 &:extend(选择器) 语法将扩展放置在规则集的主体中。将扩展放置在主体中是将其放置在该规则集的每个选择器中的快捷方式。

规则集内部的扩展:

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

与在每个选择器后添加扩展完全相同:

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

扩展嵌套选择器

Extend 能够匹配嵌套选择器。以下 Less 代码:

示例:

.bucket {
  tr { // 带有目标选择器的嵌套规则集
    color: blue;
  }
}
.some-class:extend(.bucket tr) {} // 识别嵌套规则集

输出

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

本质上,扩展查看编译后的 CSS,而不是原始的 Less。

示例:

.bucket {
  tr & { // 带有目标选择器的嵌套规则集
    color: blue;
  }
}
.some-class:extend(tr .bucket) {} // 识别嵌套规则集

输出

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

使用 Extend 的精确匹配

Extend 默认查找选择器之间的精确匹配。选择器是否使用前导星号是很重要的。两个 nth 表达式具有相同的含义并不重要,它们需要具有相同的形式才能匹配。唯一的例外是属性选择器中的引号,Less 知道它们具有相同的含义并匹配它们。

示例:

.a.class,
.class.a,
.class > .a {
  color: blue;
}
.test:extend(.class) {} // 这将不匹配上面的任何选择器

前导星号很重要。选择器 *.class.class 是等效的,但扩展不会匹配它们:

*.class {
  color: blue;
}
.noStar:extend(.class) {} // 这将不匹配 *.class 选择器

输出

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

Extend "all"

当你在扩展参数的最后指定 all 关键字时,它告诉 Less 将该选择器作为另一个选择器的一部分进行匹配。选择器将被复制,并且只有匹配的选择器部分将被替换为扩展,从而创建一个新的选择器。

示例:

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

.replacement:extend(.test all) {}

输出

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

你可以将这种操作模式视为本质上进行非破坏性的搜索和替换。

选择器插值与 Extend

Extend 无法匹配包含变量的选择器。如果选择器包含变量,扩展将忽略它。

但是,扩展可以附加到插值选择器上。

带有变量的选择器将不会被匹配:

@variable: .bucket;
@{variable} { // 插值选择器
  color: blue;
}
.some-class:extend(.bucket) {} // 不起作用,未找到匹配

目标选择器中带有变量的扩展将匹配不到任何内容:

.bucket {
  color: blue;
}
.some-class:extend(@{variable}) {} // 插值选择器匹配不到任何内容
@variable: .bucket;

上面两个示例都编译为:

.bucket {
  color: blue;
}

然而,附加到插值选择器的 :extend 是有效的:

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

编译为:

.bucket, .selector {
  color: blue;
}

作用域 / @media 内的 Extend

目前,@media 声明中的 :extend 只会匹配同一媒体声明中的选择器:

@media print {
  .screenClass:extend(.selector) {} // 媒体内的扩展
  .selector { // 这将被匹配 - 它在同一媒体中
    color: black;
  }
}
.selector { // 样式表顶部的规则集 - 扩展忽略它
  color: red;
}
@media screen {
  .selector {  // 另一个媒体中的规则集 - 扩展忽略它
    color: blue;
  }
}

编译为:

@media print {
  .selector,
  .screenClass { /*  同一媒体中的规则集被扩展 */
    color: black;
  }
}
.selector { /* 样式表顶部的规则集被忽略 */
  color: red;
}
@media screen {
  .selector { /* 另一个媒体中的规则集被忽略 */
    color: blue;
  }
}

注意:扩展不会匹配嵌套 @media 声明中的选择器:

@media screen {
  .screenClass:extend(.selector) {} // 媒体内的扩展
  @media (min-width: 1023px) {
    .selector {  // 嵌套媒体中的规则集 - 扩展忽略它
      color: blue;
    }
  }
}

这编译为:

@media screen and (min-width: 1023px) {
  .selector { /* 另一个嵌套媒体中的规则集被忽略 */
    color: blue;
  }
}

顶层扩展匹配所有内容,包括嵌套媒体中的选择器:

@media screen {
  .selector {  /* 嵌套媒体中的规则集 - 顶层扩展有效 */
    color: blue;
  }
  @media (min-width: 1023px) {
    .selector {  /* 嵌套媒体中的规则集 - 顶层扩展有效 */
      color: blue;
    }
  }
}

.topLevel:extend(.selector) {} /* 顶层扩展匹配所有内容 */

编译为:

@media screen {
  .selector,
  .topLevel { /* 媒体中的规则集被扩展 */
    color: blue;
  }
}
@media screen and (min-width: 1023px) {
  .selector,
  .topLevel { /* 嵌套媒体中的规则集被扩展 */
    color: blue;
  }
}

重复检测

目前没有重复检测。

示例:

.alert-info,
.widget {
  /* 声明 */
}

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

输出

.alert-info,
.widget,
.alert,
.alert {
  /* 声明 */
}

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 并在 Less 中使用扩展。例如:

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

减少 CSS 大小

混合(Mixins)会将所有属性复制到选择器中,这可能导致不必要的重复。因此,你可以使用扩展而不是混合,将选择器移动到你想要使用的属性上,这会导致生成更少的 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 {
  // 列表样式
}
button.list-style {
  &:extend(li.list > a); // 使用相同的列表样式
}

合并属性

Edit the markdown source for "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 要求在每个待连接的声明上显式使用 ++_ 标志。


混合器

Edit the markdown source for "mixins"

从现有样式中"混入"属性

你可以混入类选择器和 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;    // 目前有效,但已弃用;请勿使用
.a (); // 括号前的空白也已弃用

带括号的混合

如果你想创建一个混合,但不希望该混合出现在你的 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(); // 已弃用
#outer .inner();   // 已弃用
#outer.inner();    // 推荐

以这种方式为你的混合命名空间可以减少与其他库混合或用户混合的冲突,同时也是"组织"混合组的一种方式。

示例:

#my-library {
  .my-mixin() {
    color: black;
  }
}
// 可以这样使用
.class {
  #my-library.my-mixin();
}

受保护的命名空间

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

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

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

对于所有嵌套的命名空间和混合,default 函数被假定具有相同的值。以下混合永远不会被评估;其中一个保护条件保证为 false:

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

!important 关键字

在混合调用后使用 !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;
}

参数混合器

Edit the markdown source for "mixins-parametric"

如何向混合中传递参数

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

例如:

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

下面是我们如何将它混合到各种规则集中:

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

参数化混合还可以为其参数设置默认值:

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

现在我们可以这样调用它:

#header {
  .border-radius();
}

它将包含 5px 的边框圆角。

你还可以使用不带参数的参数化混合。如果你想从 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)
  • 使用虚拟分号创建一个包含逗号分隔的 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))

混合重载

定义具有相同名称和参数数量的多个混合是合法的。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(...) {        // 匹配 0-N 个参数
.mixin() {           // 精确匹配 0 个参数
.mixin(@a: 1) {      // 匹配 0-1 个参数
.mixin(@a: 1, ...) { // 匹配 0-N 个参数
.mixin(@a, ...) {    // 匹配 1-N 个参数

此外:

.mixin(@a, @rest...) {
   // @rest 绑定 @a 之后的参数
   // @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


使用混合器作为函数

Edit the markdown source for "mixins-as-functions"

从混合调用中选择属性和变量

属性/值访问器

发布于 v3.5.0

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

示例:

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

div {
  // 调用混合并查找其 "@result" 值
  padding: .average(16px, 50px)[@result];
}

结果是:

div {
  padding: 33px;
}

覆盖混合值

如果你有多个匹配的混合,所有规则都会被评估和合并,并返回具有该标识符的最后一个匹配值。这类似于 CSS 中的级联,并允许你"覆盖"混合值。

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

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

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

输出:

.box {
  my-value: bar;
}

未命名查找

如果你在 [@lookup] 中不指定查找值,而是在混合或规则集调用后写 [],则所有值将级联,并选择最后声明的值。

意味着:上面示例中的平均混合可以写成:

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

div {
  // 调用混合并查找其最终值
  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; // 调用者父作用域 - 无保护

结果是:

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

最后,在混合中定义的混合也可以作为返回值:

.unlock(@value) { // 外部混合
  .doSomething() { // 嵌套混合
    declaration: @value;
  }
}

#namespace {
  .unlock(5); // 解锁 doSomething 混合
  .doSomething(); // 嵌套混合已复制到此处并可使用
}

结果是:

#namespace {
  declaration: 5;
}

递归混合器

Edit the markdown source for "mixin-loops"

创建循环

在 Less 中,混合(Mixin)可以调用自身。这种递归混合,结合守卫表达式模式匹配,可以用来创建各种迭代/循环结构。

示例:

.loop(@counter) when (@counter > 0) {
  .loop((@counter - 1));    // 下一次迭代
  width: (10px * @counter); // 每次迭代的代码
}

div {
  .loop(5); // 启动循环
}

输出:

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

使用递归循环生成 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%;
}

混合器守卫

Edit the markdown source for "mixin-guards"

守卫对于希望匹配表达式很有用,而不仅仅是简单的值或参数数量。如果你熟悉函数式编程,你可能已经遇到过它们了。

为了尽可能接近 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); // 不会匹配上述任何定义。
}

注意,你还可以比较参数之间的值,或与非参数值比较:

@media: mobile;

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

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

守卫逻辑运算符

你可以对守卫使用逻辑运算符。语法基于 CSS 媒体查询。

使用 and 关键字组合守卫:

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

你可以通过用逗号 , 分隔守卫来模拟 运算符。如果任何一个守卫求值为真,则视为匹配:

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

使用 not 关键字否定条件:

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

类型检查函数

最后,如果你想基于值类型匹配混合,可以使用 is 函数:

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

以下是基本的类型检查函数:

  • iscolor
  • isnumber
  • isstring
  • iskeyword
  • isurl

如果你想检查一个值是否为特定单位的数字,可以使用以下函数之一:

  • ispixel
  • ispercentage
  • isem
  • isunit

混合器别名

Edit the markdown source for "mixins-aliasing"

发布于 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();   // 错误:无法评估变量调用 @alias
}

这是因为变量是被分配选择器列表还是混合调用是不明确的。例如,在 Less 3.5+ 中,这个变量可以这样使用。

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

上面将输出:

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

分离规则集

Edit the markdown source for "detached-rulesets"

将规则集赋值给变量

发布于 v1.7.0

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

简单示例:

// 声明分离规则集
@detached-ruleset: { background: red; }; // 在 3.5.0+ 版本中分号是可选的

// 使用分离规则集
.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: { 
    .mixin() {
        color: blue;
    }
};
// 调用分离规则集
.caller {
    @detached-ruleset(); 
    .mixin();
}

结果为:

.caller {
  color: blue;
}

私有变量:

@detached-ruleset: { 
    @color:blue; // 这个变量是私有的
};
.caller {
    color: @color; // 语法错误
}

作用域

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

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

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

注意:通过调用的混合解锁变量到作用域的方式已被弃用。请使用属性/变量访问器

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

分离规则集可以看到调用者的变量和混合:

@detached-ruleset: {
  caller-variable: @caller-variable; // 这里变量是未定义的
  .caller-mixin(); // 这里混合是未定义的
};

selector {
  // 使用分离规则集
  @detached-ruleset(); 

  // 定义分离规则集内部需要的变量和混合
  @caller-variable: value;
  .caller-mixin() {
    variable: declaration;
  }
}

编译为:

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

从定义中可访问的变量和混合优先于调用者中可用的:

@variable: global;
@detached-ruleset: {
  // 将使用全局变量,因为它可以从
  // 分离规则集定义中访问
  variable: @variable; 
};

selector {
  @detached-ruleset();
  @variable: value; // 调用者中定义的变量 - 将被忽略
}

编译为:

selector {
  variable: global;
}

引用不会修改分离规则集作用域

规则集不会仅通过在那里被引用就获得新的作用域:

@detached-1: { scope-detached: @one @two; };
.one {
  @one: visible;
  .two {
    @detached-2: @detached-1; // 复制/重命名规则集 
    @two: visible; // 规则集无法看到这个变量
  }
}

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

抛出错误:

错误 1:32 变量 "@one" 未声明。

解锁将会修改分离规则集作用域

分离规则集通过在作用域内解锁(导入)来获得访问权:

#space {
  .importer-1() {
    @detached: { scope-detached: @variable; }; // 定义分离规则集
  }
}

.importer-2() {
  @variable: value; // 解锁的分离规则集可以看到这个变量
  #space > .importer-1(); // 解锁/导入分离规则集
}

.use-place {
  .importer-2(); // 第二次解锁/导入分离规则集
   @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;
}

映射

Edit the markdown source for "maps"

发布于 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;
}

作用域

Edit the markdown source for "scope"

Less 的一些额外作用域特性

混合作用域特性

直观地说,混合可以访问定义时的作用域。

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

/* 输出:
.rule {
  prop: one;
}
*/

已弃用的混合作用域特性

以下是可能在未来版本中被移除的混合作用域特性。

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

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

这是反直觉的,因为:

  1. 在大多数其他语言中不是典型的行为。
  2. 从定义处看,不能立即明确混合将产生什么输出。

推荐方法:传入你希望对混合可见的变量。

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

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

混合会将其变量推送到调用者作用域,但_仅在_该变量未在本地定义的情况下。

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

这是反直觉的,因为:

  1. 调用者作用域中更高层的变量可能会被覆盖。
  2. 这不是典型的语言行为。
  3. 它与分离规则集的行为不同。

另外,随着映射(Maps)的引入,你可以直接检索变量值(和混合)。

推荐方法

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

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

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

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

推荐方法:直接调用混合。

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

技巧与窍门

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

这里有一个定义变量并将它们保持在私有作用域中的技巧,防止它们泄漏到全局空间。

& {
  // 变量
  @height: 100px;
  @width: 20px;
  // 不要在此作用域定义任何属性(这样做会生成(错误的)输出)。

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

.rest {
  height: @height; // 名称错误:未定义变量 @height
}

在这里,@height@width 仅在 & { ... } 创建的作用域中定义。你还可以在规则内嵌套一个作用域:

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

  & {
    // 覆盖原始值
    @height: 100px;
    @width: auto;

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

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

  & {
    // 覆盖原始值
    @height: 50px;

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

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

CSS 守卫

Edit the markdown source for "css-guards"

选择器周围的"if"

发布于 v1.5.0

与混合守卫(Mixin Guards)类似,守卫也可以应用于 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();

@plugin 规则

Edit the markdown source for "plugins"

发布于 v2.5.0

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

编写你的第一个插件

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

@plugin "my-plugin";  // 如果没有扩展名,自动追加 .js

由于 Less 插件在 Less 作用域内被评估,插件定义可以相当简单。

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

或者你可以使用 module.exports(已经过 shim 处理,可以在浏览器和 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;
    });
}
// 等等

恭喜!你已经编写了一个 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);  // 我将稍后存储这个
    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 插件应导出一个具有以下一个或多个属性的对象。

{
    /* 在插件首次导入后立即调用,仅一次。 */
    install: function(less, pluginManager, functions) { },

    /* 为你的每个 @plugin 实例调用。 */
    use: function(context) { },

    /* 为你的每个 @plugin 实例调用,
     * 在评估规则时。
     * 它只是评估生命周期的后期 */
    eval: function(context) { },

    /* 将任意字符串传递给你的插件
     * 例如 @plugin (args) "file";
     * 这个字符串不会为你解析,
     * 所以它可以包含(几乎)任何内容 */
    setOptions: function(argumentString) { },

    /* 设置最小 Less 兼容性字符串
     * 你也可以使用数组,如 [3, 0] */
    minVersion: ['3.0'],

    /* 仅用于 lessc,
     * 在终端中解释选项 */
    printUsage: function() { },

}