概述

LESS 语言特性的深入指南。有关 Less 的快速摘要,请参阅 概述

¥An in-depth guide to features of the LESS language. See the Overview for a quick summary of Less.

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

¥For an in-depth guide to installing and setting up a Less environment, as well as documentation on developing for Less, see: Using Less.js.


变量

在单个位置控制常用值。

¥Control commonly used values in a single location.

概述

¥Overview

相同的值在你的样式表中重复数十次甚至数百次的情况并不少见:

¥It's not uncommon to see the same value repeated dozens if not hundreds of times across your stylesheets:

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

变量为你提供了一种从单个位置控制这些值的方法,从而使你的代码更易于维护:

¥Variables make your code easier to maintain by giving you a way to control those values from a single location:

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

可变插值

¥Variable Interpolation

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

¥The examples above focused on using variables to control values in CSS rules, but they can also be used in other places as well, such as selector names, property names, URLs and @import statements.

选择器

¥Selectors

v1.4.0

// Variables
@my-selector: banner;

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

编译为:

¥Compiles to:

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

URLs

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

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

导入语句

¥Import Statements

v1.4.0

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

¥Syntax: @import "@{themes}/tidal-wave.less";

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

¥Note that before v2.0.0, only variables which have been declared in the root or current scope were considered and that only the current file and calling files were considered when looking for a variable.

示例:

¥Example:

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

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

属性

¥Properties

v1.6.0

@property: color;

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

编译为:

¥Compiles to:

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

可变变量

¥Variable Variables

在 Less 中,你可以使用另一个变量定义一个变量的名称。

¥In Less, you can define a variable's name using another variable.

@primary:  green;
@secondary: blue;

.section {
  @color: primary;

  .element {
    color: @@color;
  }
}

编译为:

¥Which compiles to:

.section .element {
  color: green;
}

延迟评估

¥Lazy Evaluation

变量在使用前不必声明。

¥Variables do not have to be declared before being used.

有效的 Less 片段:

¥Valid Less snippet:

.lazy-eval {
  width: @var;
}

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

这也是有效的 Less:

¥this is valid Less too:

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

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

都编译成:

¥both compile into:

.lazy-eval {
  width: 9%;
}

两次定义变量时,使用变量的最后定义,从当前作用域向上搜索。这类似于 css 本身,其中定义中的最后一个属性用于确定值。

¥When defining a variable twice, the last definition of the variable is used, searching from the current scope upwards. This is similar to css itself where the last property inside a definition is used to determine the value.

例如:

¥For instance:

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

编译为:

¥Compiles to:

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

本质上,每个作用域都有一个 "final" 值,类似于浏览器中的属性,就像这个使用自定义属性的例子:

¥Essentially, each scope has a "final" value, similar to properties in the browser, like this example using custom properties:

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

这意味着,与其他 CSS 预处理语言不同,Less 变量的行为与 CSS 非常相似。

¥This means that, unlike other CSS pre-processing languages, Less variables behave very much like CSS's.

属性作为变量(新!)

¥Properties as Variables (NEW!)

v3.0.0

你可以使用 $prop 语法轻松地将属性视为变量。有时这可以使你的代码更轻一些。

¥You can easily treat properties like variables using the $prop syntax. Sometimes this can make your code a little lighter.

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

编译为:

¥Compiles to:

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

请注意,与变量一样,Less 将选择当前/父作用域内的最后一个属性作为 "final" 值。

¥Note that, like variables, Less will choose the last property within the current/parent scope as being the "final" value.

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

由于 延迟加载,这工作正常 - @base-color 被覆盖,@dark-color 为深红色。

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


父级选择器

使用 & 引用父选择器

¥Referencing parent selectors with &

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

¥The & operator represents the parent selectors of a nested rule and is most commonly used when applying a modifying class or pseudo-class to an existing selector:

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

结果是:

¥results in:

a {
  color: blue;
}

a:hover {
  color: green;
}

请注意,如果没有 &,上面的示例将导致 a :hover 规则(匹配 <a> 标签内的悬停元素的后代选择器),这不是我们通常想要的嵌套 :hover

¥Notice that without the &, the above example would result in a :hover rule (a descendant selector that matches hovered elements inside of <a> tags) and this is not what we typically would want with the nested :hover.

"父选择器" 运算符有多种用途。基本上任何时候你需要以默认方式之外的其他方式组合嵌套规则的选择器。例如,& 的另一个典型用途是生成重复的类名:

¥The "parent selectors" operator has a variety of uses. Basically any time you need the selectors of the nested rules to be combined in other ways than the default. For example another typical use of the & is to produce repetitive class names:

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

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

输出:

¥output:

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

多个 &

¥Multiple &

& 可能会在一个选择器中出现多次。这使得重复引用父选择器而不重复其名称成为可能。

¥& may appear more than once within a selector. This makes it possible to repeatedly refer to a parent selector without repeating its name.

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

  & & {
    color: green;
  }

  && {
    color: blue;
  }

  &, &ish {
    color: cyan;
  }
}

将输出:

¥will output:

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

请注意,& 代表所有父选择器(不仅仅是最近的祖级)所以下面的例子:

¥Note that & represents all parent selectors (not just the nearest ancestor) so the following example:

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

    & & {
      color: green;
    }

    && {
      color: blue;
    }

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

结果是:

¥results in:

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

更改选择器顺序

¥Changing Selector Order

将选择器添加到继承的(父)选择器之前可能很有用。这可以通过将 & 放在当前选择器之后来完成。例如,在使用 Modernizr 时,你可能希望根据支持的功能指定不同的规则:

¥It can be useful to prepend a selector to the inherited (parent) selectors. This can be done by putting the & after current selector. For example, when using Modernizr, you might want to specify different rules based on supported features:

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

选择器 .no-borderradius & 会将 .no-borderradius 添加到其父 .header .menu 的前面,以在输出中形成 .no-borderradius .header .menu

¥The selector .no-borderradius & will prepend .no-borderradius to its parent .header .menu to form the.no-borderradius .header .menu on output:

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

组合爆炸

¥Combinatorial Explosion

& 也可用于在逗号分隔列表中生成选择器的所有可能排列:

¥& can also be used to generate every possible permutation of selectors in a comma separated list:

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

这扩展到指定元素的所有可能 (16) 组合:

¥This expands to all possible (16) combinations of the specified elements:

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 规则

从其他样式表导入样式

¥Import styles from other style sheets

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

¥In standard CSS, @import at-rules must precede all other types of rules. But Less doesn't care where you put @import statements.

示例:

¥Example:

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

文件扩展名

¥File Extensions

Less 可能会根据文件扩展名对 @import 语句进行不同的处理:

¥@import statements may be treated differently by Less depending on the file extension:

  • 如果文件有 .css 扩展名,它将被视为 CSS 并且 @import 语句保持原样(参见下面的 内联选项)。

    ¥If the file has a .css extension it will be treated as CSS and the @import statement left as-is (see the inline option below).

  • 如果它有任何其他扩展名,它将被视为 Less 并导入。

    ¥If it has any other extension it will be treated as Less and imported.

  • 如果它没有扩展名,则会附加 .less 并将其作为导入的 Less 文件包含在内。

    ¥If it does not have an extension, .less will be appended and it will be included as a imported Less file.

示例:

¥Examples:

@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

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

¥The following options can be used to override this behavior.

导入选项

¥Import Options

Less 为 CSS @import CSS @ 规则提供了几个扩展,以提供比你可以对外部文件执行的操作更大的灵活性。

¥Less offers several extensions to the CSS @import CSS at-rule to provide more flexibility over what you can do with external files.

语法:@import (keyword) "filename";

¥Syntax: @import (keyword) "filename";

已实现以下导入选项:

¥The following import options have been implemented:

  • reference:使用 Less 文件但不输出它

    ¥reference: use a Less file but do not output it

  • inline:在输出中包含源文件但不处理它

    ¥inline: include the source file in the output but do not process it

  • less:将文件视为 Less 文件,无论文件扩展名是什么

    ¥less: treat the file as a Less file, no matter what the file extension

  • css:将文件视为 CSS 文件,无论文件扩展名是什么

    ¥css: treat the file as a CSS file, no matter what the file extension

  • once:只包含文件一次(这是默认行为)

    ¥once: only include the file once (this is default behavior)

  • multiple:多次包含文件

    ¥multiple: include the file multiple times

  • optional:找不到文件时继续编译

    ¥optional: continue compiling when file is not found

每个 @import 允许多个关键字,你必须使用逗号分隔关键字:

¥More than one keyword per @import is allowed, you will have to use commas to separate the keywords:

示例:@import (optional, reference) "foo.less";

¥Example: @import (optional, reference) "foo.less";

reference

使用 @import (reference) 导入外部文件,但除非引用,否则不将导入的样式添加到编译输出。

¥Use @import (reference) to import external files, but without adding the imported styles to the compiled output unless referenced.

发布于 v1.5.0

¥Released v1.5.0

示例:@import (reference) "foo.less";

¥Example: @import (reference) "foo.less";

想象一下,reference 在导入文件中用引用标志标记每个 at-rule 和选择器,正常导入,但是当生成 CSS 时,"reference" 选择器(以及任何仅包含引用选择器的媒体查询)不会输出。reference 样式不会出现在你生成的 CSS 中,除非引用样式用作 mixinsextended

¥Imagine that reference marks every at-rule and selector with a reference flag in the imported file, imports as normal, but when the CSS is generated, "reference" selectors (as well as any media queries containing only reference selectors) are not output. reference styles will not show up in your generated CSS unless the reference styles are used as mixins or extended.

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

¥Additionally, reference produces different results depending on which method was used (mixin or extend):

  • extend:当一个选择器被扩展时,只有新的选择器被标记为未被引用,并被拉入引用 @import 语句的位置。

    ¥extend: When a selector is extended, only the new selector is marked as not referenced, and it is pulled in at the position of the reference @import statement.

  • mixins:当 reference 样式用作 隐式混合 时,其规则被混入,标记为 "不引用",并正常出现在引用的位置。

    ¥mixins: When a reference style is used as an implicit mixin, its rules are mixed-in, marked "not reference", and appear in the referenced place as normal.

参考范例

¥reference example

这允许你通过执行以下操作仅从 Bootstrap 等库中提取特定的、有针对性的样式:

¥This allows you to pull in only specific, targeted styles from a library such as Bootstrap by doing something like this:

.navbar:extend(.navbar all) {}

并且你将从 Bootstrap 中仅引入与 .navbar 相关的样式。

¥And you will pull in only .navbar related styles from Bootstrap.

inline

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

¥Use @import (inline) to include external files, but not process them.

发布于 v1.5.0

¥Released v1.5.0

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

¥Example: @import (inline) "not-less-compatible.css";

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

¥You will use this when a CSS file may not be Less compatible; this is because although Less supports most known standards CSS, it does not support comments in some places and does not support all known CSS hacks without modifying the CSS.

因此,你可以使用它在输出中包含文件,以便所有 CSS 都在一个文件中。

¥So you can use this to include the file in the output so that all CSS will be in one file.

less

使用 @import (less) 将导入的文件视为 Less,而不考虑文件扩展名。

¥Use @import (less) to treat imported files as Less, regardless of file extension.

发布于 v1.4.0

¥Released v1.4.0

示例:

¥Example:

@import (less) "foo.css";

css

使用 @import (css) 将导入的文件视为常规 CSS,而不考虑文件扩展名。这意味着导入语句将保持原样。

¥Use @import (css) to treat imported files as regular CSS, regardless of file extension. This means the import statement will be left as it is.

发布于 v1.4.0

¥Released v1.4.0

示例:

¥Example:

@import (css) "foo.less";

输出

¥outputs

@import "foo.less";

once

@import 语句的默认行为。这意味着该文件仅导入一次,该文件的后续导入语句将被忽略。

¥The default behavior of @import statements. It means the file is imported only once and subsequent import statements for that file will be ignored.

发布于 v1.4.0

¥Released v1.4.0

这是 @import 语句的默认行为。

¥This is the default behavior of @import statements.

示例:

¥Example:

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

multiple

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

¥Use @import (multiple) to allow importing of multiple files with the same name. This is the opposite behavior to once.

发布于 v1.4.0

¥Released v1.4.0

示例:

¥Example:

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

输出

¥Outputs

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

optional

使用 @import (optional) 允许仅在文件存在时导入该文件。如果没有 optional 关键字,Less 会在导入找不到的文件时抛出 FileError 并停止编译。

¥Use @import (optional) to allow importing of a file only when it exists. Without the optional keyword Less throws a FileError and stops compiling when importing a file that can not be found.

发布于 v2.3.0

¥Released v2.3.0


继承

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

¥Extend is a Less pseudo-class which merges the selector it is put on with ones that match what it references.

发布于 v1.4.0

¥Released v1.4.0

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

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

¥In the rule set above, the :extend selector will apply the "extending selector" (nav ul) onto the .inline class wherever the .inline class appears. The declaration block will be kept as-is, but without any reference to the extend (because extend isn't css).

所以如下:

¥So the following:

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

输出

¥Outputs

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

注意 nav ul:extend(.inline) 选择器如何获得 nav ul 的输出 - 扩展在输出之前被删除,选择器块保持原样。如果该块中没有放置任何属性,那么它将从输出中删除(但扩展仍然可能影响其他选择器)。

¥Notice how the nav ul:extend(.inline) selector gets output as nav ul - the extend gets removed before output and the selector block left as-is. If no properties are put in that block then it gets removed from the output (but the extend still may affect other selectors).

继承语法

¥Extend Syntax

扩展要么附加到选择器,要么放入规则集中。它看起来像一个带有选择器参数的伪类,可选地后跟关键字 all

¥The extend is either attached to a selector or placed into a ruleset. It looks like a pseudo-class with selector parameter optionally followed by the keyword all:

示例:

¥Example:

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

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

¥It can contain one or more classes to extend, separated by commas.

示例:

¥Example:

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

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

继承附加到选择器

¥Extend Attached to Selector

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

¥Extend attached to a selector looks like an ordinary pseudo-class with selector as a parameter. A selector can contain multiple extend clauses, but all extends must be at the end of the selector.

  • 在选择器之后扩展:pre:hover:extend(div pre)

    ¥Extend after the selector: pre:hover:extend(div pre).

  • 选择器和扩展之间的空间是允许的:pre:hover :extend(div pre)

    ¥Space between selector and extend is allowed: pre:hover :extend(div pre).

  • 允许多个扩展:pre:hover:extend(div pre):extend(.bucket tr) - 注意这与 pre:hover:extend(div pre, .bucket tr) 相同

    ¥Multiple extends are allowed: pre:hover:extend(div pre):extend(.bucket tr) - Note this is the same as pre:hover:extend(div pre, .bucket tr)

  • 这是不允许的:pre:hover:extend(div pre).nth-child(odd)。扩展必须在最后。

    ¥This is NOT allowed: pre:hover:extend(div pre).nth-child(odd). Extend must be last.

如果规则集包含多个选择器,则其中任何一个都可以具有 extend 关键字。在一个规则集中扩展的多个选择器:

¥If a ruleset contains multiple selectors, any of them can have the extend keyword. Multiple selectors with extend in one ruleset:

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

继承内部规则集

¥Extend Inside Ruleset

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

¥Extend can be placed into a ruleset's body using &:extend(selector) syntax. Placing extend into a body is a shortcut for placing it into every single selector of that ruleset.

在主体内继承:

¥Extend inside a body:

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

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

¥is exactly the same as adding an extend after each selector:

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

继承嵌套选择器

¥Extending Nested Selectors

Extend 能够匹配嵌套的选择器。关注 less:

¥Extend is able to match nested selectors. Following less:

示例:

¥Example:

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

输出

¥Outputs

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

本质上,extend 着眼于编译后的 css,而不是原始的 less。

¥Essentially the extend looks at the compiled css, not the original less.

示例:

¥Example:

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

输出

¥Outputs

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

精确匹配继承

¥Exact Matching with Extend

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

¥Extend by default looks for exact match between selectors. It does matter whether selector uses leading star or not. It does not matter that two nth-expressions have the same meaning, they need to have to same form in order to be matched. The only exception are quotes in attribute selector, less knows they have the same meaning and matches them.

示例:

¥Example:

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

明星确实很重要。选择器 *.class.class 是等价的,但 extend 不会匹配它们:

¥Leading star does matter. Selectors *.class and .class are equivalent, but extend will not match them:

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

输出

¥Outputs

*.class {
  color: blue;
}

伪类的顺序确实很重要。选择器 link:hover:visitedlink:visited:hover 匹配同一组元素,但 extend 将它们视为不同的:

¥Order of pseudo-classes does matter. Selectors link:hover:visited and link:visited:hover match the same set of elements, but extend treats them as different:

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

输出

¥Outputs

link:hover:visited {
  color: blue;
}

第 n 个表达式

¥nth Expression

第 N 种表达形式很重要。第 N 个表达式 1n+3n+3 是等价的,但扩展不会匹配它们:

¥Nth expression form does matter. Nth-expressions 1n+3 and n+3 are equivalent, but extend will not match them:

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

输出

¥Outputs

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

属性选择器中的引用类型无关紧要。以下所有内容都是等价的。

¥Quote type in attribute selector does not matter. All of the following are equivalent.

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

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

输出

¥Outputs

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

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

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

继承 "all"

¥Extend "all"

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

¥When you specify the all keyword last in an extend argument it tells Less to match that selector as part of another selector. The selector will be copied and the matched part of the selector only will then be replaced with the extend, making a new selector.

示例:

¥Example:

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

.replacement:extend(.test all) {}

输出

¥Outputs

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

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

¥You can think of this mode of operation as essentially doing a non-destructive search and replace.

继承选择器插值

¥Selector Interpolation with Extend

Extend is not 能够将选择器与变量相匹配。如果选择器包含变量,extend 将忽略它。

¥able to match selectors with variables. If selector contains variable, extend will ignore it.

但是,extend 可以附加到插值选择器。

¥However, extend can be attached to interpolated selector.

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

¥Selector with variable will not be matched:

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

并在目标选择器中使用变量扩展不匹配:

¥and extend with variable in target selector matches nothing:

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

以上两个例子编译成:

¥Both of the above examples compile into:

.bucket {
  color: blue;
}

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

¥However, :extend attached to an interpolated selector works:

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

编译为:

¥compiles to:

.bucket, .selector {
  color: blue;
}

作用域/继承内部 @media

¥Scoping / Extend Inside @media

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

¥Currently, an :extend inside a @media declaration will only match selectors inside the same media declaration:

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

编译成:

¥compiles into:

@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 声明内的选择器不匹配:

¥Note: extending does not match selectors inside a nested @media declaration:

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

这编译成:

¥This compiles into:

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

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

¥Top level extend matches everything including selectors inside nested 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 */

编译成:

¥compiles into:

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

重复检测

¥Duplication Detection

目前没有重复检测。

¥Currently there is no duplication detection.

示例:

¥Example:

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

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

输出

¥Outputs

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

继承的用例

¥Use Cases for Extend

经典用例

¥Classic Use Case

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

¥The classic use case is to avoid adding a base class. For example, if you have

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

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

¥and you want to have a subtype of animal which overrides the background color then you have two options, firstly change your HTML

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

或者简化 html 并在你的 less 中使用 extend。例如

¥or have simplified html and use extend in your less. e.g.

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

减少 CSS 大小

¥Reducing CSS Size

Mixins 将所有属性复制到一个选择器中,这会导致不必要的重复。因此,你可以使用 extends 而不是 mixins 将选择器向上移动到你希望使用的属性,这会导致生成更少的 CSS。

¥Mixins copy all of the properties into a selector, which can lead to unnecessary duplication. Therefore you can use extends instead of mixins to move the selector up to the properties you wish to use, which leads to less CSS being generated.

示例 - 与混合:

¥Example - with mixin:

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

输出

¥Outputs

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

示例(带扩展):

¥Example (with extends):

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

输出

¥Outputs

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

组合样式/更高级的混合

¥Combining Styles / A More Advanced Mixin

另一个用例是作为 mixin 的替代品 - 因为 mixins 只能与简单的选择器一起使用,所以如果你有两个不同的 html 块,但需要对两个块应用相同的样式,则可以使用 extends 来关联两个区域。

¥Another use-case is as an alternative for a mixin - because mixins can only be used with simple selectors, if you have two different blocks of html, but need to apply the same styles to both you can use extends to relate two areas.

示例:

¥Example:

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

合并属性

合并属性

¥Combine properties

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

¥The merge feature allows for aggregating values from multiple properties into a comma or space separated list under a single property. merge is useful for properties such as background and transform.

逗号

¥Comma

用逗号附加属性值

¥Append property value with comma

发布于 v1.5.0

¥Released v1.5.0

示例:

¥Example:

.mixin() {
  box-shadow+: inset 0 0 10px #555;
}
.myclass {
  .mixin();
  box-shadow+: 0 0 20px black;
}

输出

¥Outputs

.myclass {
  box-shadow: inset 0 0 10px #555, 0 0 20px black;
}

空格

¥Space

用空格附加属性值

¥Append property value with space

发布于 v1.7.0

¥Released v1.7.0

示例:

¥Example:

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

输出

¥Outputs

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

为了避免任何无意的连接,merge 要求在每个连接挂起声明上都有一个明确的 ++_ 标志。

¥To avoid any unintentional joins, merge requires an explicit + or +_ flag on each join pending declaration.


混入

现有样式的 "mix-in" 属性

¥"mix-in" properties from existing styles

你可以混合使用类选择器和 ID 选择器,例如

¥You can mix-in class selectors and id selectors, e.g.

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

结果是:

¥which results in:

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

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

¥Historically, the parentheses in a mixin call are optional, but optional parentheses are deprecated and will be required in a future release.

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

带括号的混入

¥Mixins With Parentheses

如果你想创建一个 mixin 但你不希望那个 mixin 出现在你的 CSS 输出中,请在 mixin 定义之后加上括号。

¥If you want to create a mixin but you do not want that mixin to be in your CSS output, put parentheses after the mixin definition.

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

输出

¥outputs

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

混入中的选择器

¥Selectors in Mixins

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

¥Mixins can contain more than just properties, they can contain selectors too.

例如:

¥For example:

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

输出

¥Outputs

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

命名空间

¥Namespaces

如果你想在更复杂的选择器中混合属性,你可以堆叠多个 id 或类。

¥If you want to mixin properties inside a more complicated selector, you can stack up multiple ids or classes.

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

.c {
  #outer.inner();
}

注意:旧版的 Less 语法允许 > 和名称空间与混入之间的空格。此语法已弃用,可能会被删除。目前,这些做同样的事情。

¥Note: legacy Less syntax allows > and whitespace between namespaces and mixins. This syntax is deprecated and may be removed. Currently, these do the same thing.

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

像这样命名你的混入可以减少与其他库混入或用户混入的冲突,但也可以成为 "organize" 组混入的一种方式。

¥Namespacing your mixins like this reduces conflicts with other library mixins or user mixins, but can also be a way to "organize" groups of mixins.

示例:

¥Example:

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

受保护的命名空间

¥Guarded Namespaces

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

¥If a namespace has a guard, mixins defined by it are used only if the guard condition returns true. A namespace guard is evaluated exactly the same as a guard on a mixin, so the following two mixins work the same way:

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

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

假定 default 函数对所有嵌套命名空间和混入具有相同的值。下面的 mixin 永远不会被评估;它的一名守卫保证是假的:

¥The default function is assumed to have the same value for all nested namespaces and mixin. The following mixin is never evaluated; one of its guards is guaranteed to be false:

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

!important 关键字

¥The !important keyword

在 mixin 调用后使用 !important 关键字将其继承的所有属性标记为 !important

¥Use the !important keyword after mixin call to mark all properties inherited by it as !important:

示例:

¥Example:

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

结果是:

¥Results in:

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

参数混合

如何将参数传递给 mixins

¥How to pass arguments to mixins

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

¥Mixins can also take arguments, which are variables passed to the block of selectors when it is mixed in.

例如:

¥For example:

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

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

¥And here's how we can mix it into various rulesets:

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

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

¥Parametric mixins can also have default values for their parameters:

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

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

¥We can invoke it like this now:

#header {
  .border-radius();
}

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

¥And it will include a 5px border-radius.

你还可以使用不带参数的参数混合。如果你想从 CSS 输出中隐藏规则集,但又想将其属性包含在其他规则集中,这将很有用:

¥You can also use parametric mixins which don't take parameters. This is useful if you want to hide the ruleset from the CSS output, but want to include its properties in other rulesets:

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

pre { .wrap() }

哪个会输出:

¥Which would output:

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

参数分隔符

¥Parameter separators

参数当前以分号或逗号分隔。

¥Parameters are currently either semicolon or comma separated.

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

¥Originally, parameters were only separated by commas, but the semi-colon was later added to support passing comma-separated list values to single arguments.

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

¥Note: As of Less 4.0, you can wrap a list value using a paren escape [~()], e.g. .name(@param1: ~(red, blue)). This is similar to the quote escape syntax: ~"quote". This may make semi-colon separators un-necessary in your code-base.

示例:

¥Examples:

  • 两个参数,每个参数都包含逗号分隔列表:.name(1, 2, 3; something, else)

    ¥two arguments and each contains comma separated list: .name(1, 2, 3; something, else)

  • 三个参数,每个参数包含一个数字:.name(1, 2, 3)

    ¥three arguments and each contains one number: .name(1, 2, 3)

  • 使用虚拟分号创建一个 mixin 调用,其中一个参数包含一个逗号分隔的 css 列表:.name(1, 2, 3;)。注意:如果结尾的分号看起来很奇怪,你可能更喜欢:.name(~(1, 2, 3))

    ¥use a dummy semicolon to create a mixin call with one argument containing a comma-separated css list: .name(1, 2, 3;). Note: if the trailing semi-colon seems strange, you may prefer: .name(~(1, 2, 3))

  • 编写逗号分隔默认值的方法:

    ¥Ways to write a comma separated default value:

    • @param-values: red, blue; .name(@param1: @param-values)

    • .name(@param1: red, blue;)

    • .name(@param1: ~(red, blue))

重载混入

¥Overloading mixins

定义多个具有相同名称和参数数量的混合是合法的。Less 将使用所有可以应用的属性。如果你使用带有一个参数的 mixin,例如 .mixin(green);,然后将使用具有一个强制参数的所有 mixin 的属性:

¥It is legal to define multiple mixins with the same name and number of parameters. Less will use properties of all that can apply. If you used the mixin with one parameter e.g. .mixin(green);, then properties of all mixins with exactly one mandatory parameter will be used:

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

编译成:

¥compiles into:

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

命名参数

¥Named Parameters

mixin 引用可以通过名称而不是位置来提供参数值。任何参数都可以通过其名称来引用,并且它们不必按任何特殊顺序排列:

¥A mixin reference can supply parameters values by their names instead of just positions. Any parameter can be referenced by its name and they do not have to be in any special order:

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

编译成:

¥compiles into:

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

@arguments 变量

¥The @arguments Variable

@arguments 在 mixin 中有特殊含义,它包含调用 mixin 时传递的所有参数。如果你不想处理单个参数,这很有用:

¥@arguments has a special meaning inside mixins, it contains all the arguments passed, when the mixin was called. This is useful if you don't want to deal with individual parameters:

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

结果是:

¥Which results in:

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

高级参数和 @rest 变量

¥Advanced Arguments and the @rest Variable

如果你希望你的 mixin 接受可变数量的参数,你可以使用 ...。在变量名之后使用它会将这些参数分配给变量。

¥You can use ... if you want your mixin to take a variable number of arguments. Using this after a variable name will assign those arguments to the variable.

.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

此外:

¥Furthermore:

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

模式匹配

¥Pattern-matching

有时,你可能希望根据传递给它的参数更改混入的行为。让我们从一些基本的东西开始:

¥Sometimes, you may want to change the behavior of a mixin, based on the parameters you pass to it. Let's start with something basic:

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

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

现在假设我们希望 .mixin 表现不同,基于 @switch 的值,我们可以这样定义 .mixin

¥Now let's say we want .mixin to behave differently, based on the value of @switch, we could define .mixin as such:

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

现在,如果我们运行:

¥Now, if we run:

@switch: light;

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

我们将得到以下 CSS:

¥We will get the following CSS:

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

传递给 .mixin 的颜色变浅了。如果 @switch 的值为 dark,则结果将是较深的颜色。

¥Where the color passed to .mixin was lightened. If the value of @switch was dark, the result would be a darker color.

这是发生了什么:

¥Here's what happened:

  • 第一个 mixin 定义不匹配,因为它期望 dark 作为第一个参数。

    ¥The first mixin definition didn't match because it expected dark as the first argument.

  • 第二个 mixin 定义匹配,因为它需要 light

    ¥The second mixin definition matched, because it expected light.

  • 第三个 mixin 定义匹配,因为它期望任何值。

    ¥The third mixin definition matched because it expected any value.

仅使用匹配的 mixin 定义。变量匹配并绑定到任何值。除了变量之外的任何东西都只与等于其自身的值匹配。

¥Only mixin definitions which matched were used. Variables match and bind to any value. Anything other than a variable matches only with a value equal to itself.

我们也可以匹配元数,下面是一个例子:

¥We can also match on arity, here's an example:

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

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

¥Now if we call .mixin with a single argument, we will get the output of the first definition, but if we call it with two arguments, we will get the second definition, namely @a faded to @b.


使用混入作为函数

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

¥Selecting properties and variables from mixin calls

属性/值访问器

¥Property / value accessors

发布于 v3.5.0

¥Released v3.5.0

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

¥Starting in Less 3.5, you can use property/variable accessors to select a value from an evaluated mixin's rules. This can allow you to use mixins similar to functions.

示例:

¥Example:

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

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

结果是:

¥Results in:

div {
  padding: 33px;
}

覆盖混入值

¥Overriding mixin values

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

¥If you have multiple matching mixins, all rules are evaluated and merged, and the last matching value with that identifier is returned. This is similar to the cascade in CSS, and it allows you to "override" mixin values.

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

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

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

输出:

¥Outputs:

.box {
  my-value: bar;
}

未命名的查找

¥Unnamed lookups

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

¥If you don't specify a lookup value in [@lookup] and instead write [] after a mixin or ruleset call, all values will cascade and the last declared value will be selected.

意义:上面例子中的平均 mixin 可以写成:

¥Meaning: the averaging mixin from the above example could be written as:

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

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

输出是相同的:

¥The output is the same:

div {
  padding: 33px;
}

对于混入调用别名的规则集或变量,同样的级联行为也是如此。

¥The same cascading behavior is true for rulesets or variables aliased to mixin calls.

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

这输出:

¥This outputs:

.box {
  my-value: foo;
}

将 mixins 和变量解锁到调用者作用域

¥Unlocking mixins & variables into caller scope

DEPRECATED - 使用属性/值访问器

¥DEPRECATED - Use Property / Value Accessors

mixin 中定义的变量和 mixin 是可见的,可以在调用者的作用域内使用。只有一个例外:如果调用者包含具有相同名称的变量(包括由另一个 mixin 调用定义的变量),则不会复制该变量。只有存在于调用者本地作用域内的变量才受到保护。从父作用域继承的变量被覆盖。

¥Variables and mixins defined in a mixin are visible and can be used in caller's scope. There is only one exception: a variable is not copied if the caller contains a variable with the same name (that includes variables defined by another mixin call). Only variables present in callers local scope are protected. Variables inherited from parent scopes are overridden.

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

¥Note: this behavior is deprecated, and in the future, variables and mixins will not be merged into the caller scope in this way.

示例:

¥Example:

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

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

结果是:

¥Results in:

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

不能覆盖直接在调用者作用域内定义的变量。但是,调用者父作用域中定义的变量不受保护,将被覆盖:

¥Variables defined directly in callers scope cannot be overridden. However, variables defined in callers parent scope is not protected and will be overridden:

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

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

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

结果是:

¥Results in:

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

最后,mixin 中定义的 mixin 也作为返回值:

¥Finally, mixin defined in mixin acts as return value too:

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

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

结果是:

¥Results in:

#namespace {
  declaration: 5;
}

递归混入

创建循环

¥Creating loops

在 Less 中,mixin 可以调用自己。当与 守卫表达式模式匹配 结合使用时,此类递归混合可用于创建各种迭代/循环结构。

¥In Less a mixin can call itself. Such recursive mixins, when combined with Guard Expressions and Pattern Matching, can be used to create various iterative/loop structures.

示例:

¥Example:

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

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

输出:

¥Output:

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

使用递归循环生成 CSS 网格类的通用示例:

¥A generic example of using a recursive loop to generate CSS grid classes:

.generate-columns(4);

.generate-columns(@n, @i: 1) when (@i =< @n) {
  .column-@{i} {
    width: (@i * 100% / @n);
  }
  .generate-columns(@n, (@i + 1));
}

输出:

¥Output:

.column-1 {
  width: 25%;
}
.column-2 {
  width: 50%;
}
.column-3 {
  width: 75%;
}
.column-4 {
  width: 100%;
}

混入守卫

当你想匹配表达式时,守卫很有用,而不是简单的值或元数。如果你熟悉函数式编程,你可能已经遇到过它们。

¥Guards are useful when you want to match on expressions, as opposed to simple values or arity. If you are familiar with functional programming, you have probably encountered them already.

为了尽可能接近 CSS 的声明性本质,Less 选择通过受保护的混合而不是 if/else 语句来实现条件执行,符合 @media 查询功能规范。

¥In trying to stay as close as possible to the declarative nature of CSS, Less has opted to implement conditional execution via guarded mixins instead of if/else statements, in the vein of @media query feature specifications.

让我们从一个例子开始:

¥Let's start with an example:

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

关键是 when 关键字,它引入了一个守卫序列(这里只有一个守卫)。现在,如果我们运行以下代码:

¥The key is the when keyword, which introduces a guard sequence (here with only one guard). Now if we run the following code:

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

这是我们将得到的:

¥Here's what we'll get:

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

守卫比较运算符

¥Guard Comparison Operators

守卫中可用的比较运算符的完整列表是:>>===<<。此外,关键字 true 是唯一的真值,这使得这两个 mixins 等效:

¥The full list of comparison operators usable in guards are: >, >=, =, =<, <. Additionally, the keyword true is the only truthy value, making these two mixins equivalent:

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

除关键字 true 之外的任何值都是假的:

¥Any value other than the keyword true is falsy:

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

请注意,你还可以将参数相互比较,或与非参数进行比较:

¥Note that you can also compare arguments with each other, or with non-arguments:

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

守卫逻辑运算符

¥Guard Logical Operators

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

¥You can use logical operators with guards. The syntax is based on CSS media queries.

使用 and 关键字组合守卫:

¥Use the and keyword to combine guards:

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

你可以通过用逗号 , 分隔守卫来模拟 or 运算符。如果任何一个守卫评估为真,它被认为是一场比赛:

¥You can emulate the or operator by separating guards with a comma ,. If any of the guards evaluate to true, it's considered a match:

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

使用 not 关键字否定条件:

¥Use the not keyword to negate conditions:

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

类型检查函数

¥Type Checking Functions

最后,如果你想根据值类型匹配 mixins,你可以使用 is 函数:

¥Lastly, if you want to match mixins based on value type, you can use the is functions:

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

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

¥Here are the basic type checking functions:

  • iscolor

  • isnumber

  • isstring

  • iskeyword

  • isurl

如果你想检查一个值除了是一个数字之外是否在一个特定的单位中,你可以使用以下之一:

¥If you want to check if a value is in a specific unit in addition to being a number, you may use one of:

  • ispixel

  • ispercentage

  • isem

  • isunit


混入别名

发布于 v3.5.0

¥Released v3.5.0

将 mixin 调用分配给变量

¥Assigning mixin calls to a variable

Mixins 可以赋值给一个变量来作为变量调用调用,也可以用于 map lookup。

¥Mixins can be assigned to a variable to be called as a variable call, or can be used for map lookup.

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

这将输出:

¥This would output:

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

变量调用

¥Variable calls

整个 mixin 调用都可以使用别名并称为变量调用。如:

¥Entire mixin calls can be aliased and called as variable calls. As in:

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

输出:

¥Outputs:

.box {
  background: green;
}

请注意,与 root 中使用的 mixin 不同,分配给变量和不带参数调用的 mixin 调用始终需要括号。以下内容无效。

¥Note, unlike mixins used in root, mixin calls assigned to variables and called with no arguments always require parentheses. The following is not valid.

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

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

¥This is because it's ambiguous if variable is assigned a list of selectors or a mixin call. For example, in Less 3.5+, this variable could be used this way.

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

以上将输出:

¥The above would output:

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

分离规则集

将规则集分配给变量

¥Assign a ruleset to a variable

发布于 v1.7.0

¥Released v1.7.0

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

¥A detached ruleset is a group of css properties, nested rulesets, media declarations or anything else stored in a variable. You can include it into a ruleset or another structure and all its properties are going to be copied there. You can also use it as a mixin argument and pass it around as any other variable.

简单示例:

¥Simple example:

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

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

编译成:

¥compiles into:

.top {
  background: red;
}

分离规则集调用后的括号是强制性的(除非后跟 查找值)。调用 @detached-ruleset; 不起作用。

¥Parentheses after a detached ruleset call are mandatory (except when followed by a lookup value). The call @detached-ruleset; would not work.

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

¥It is useful when you want to define a mixin that abstracts out either wrapping a piece of code in a media query or a non-supported browser class name. The rulesets can be passed to mixin so that the mixin can wrap the content, e.g.

.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 来封装一段代码。这将输出

¥Here the desktop-and-old-ie mixin defines the media query and root class so that you can use a mixin to wrap a piece of code. This will output

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

现在可以将规则集分配给变量或传递给混合,并且可以包含完整的 Less 功能集,例如

¥A ruleset can be now assigned to a variable or passed in to a mixin and can contain the full set of Less features, e.g.

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

例如,你甚至可以利用 媒体查询冒泡

¥You can even take advantage of media query bubbling, for instance

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

这将输出

¥which will output

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

一个分离的规则集调用解锁(返回)它所有的 mixin 到调用者,就像 mixin 调用一样。但是,它不返回变量。

¥A detached ruleset call unlocks (returns) all its mixins into caller the same way as mixin calls do. However, it does not return variables.

返回混入:

¥Returned mixin:

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

结果是:

¥Results in:

.caller {
  color: blue;
}

私有变量:

¥Private variables:

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

作用域

¥Scoping

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

¥A detached ruleset can use all variables and mixins accessible where it is defined and where it is called. Otherwise said, both definition and caller scopes are available to it. If both scopes contains the same variable or mixin, declaration scope value takes precedence.

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

¥Declaration scope is the one where detached ruleset body is defined. Copying a detached ruleset from one variable into another cannot modify its scope. The ruleset does not gain access to new scopes just by being referenced there.

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

¥Lastly, a detached ruleset can gain access to scope by being unlocked (imported) into it.

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

¥Note: unlocking variables into scope via a called mixin is deprecated. Use property / variable accessors.

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

¥Definition and Caller Scope Visibility

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

¥A detached ruleset sees the caller's variables and mixins:

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

编译成:

¥compiles into:

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

从定义中可访问的变量和混入胜过调用者中可用的那些:

¥Variable and mixins accessible from definition win over those available in the caller:

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

编译成:

¥compiles into:

selector {
  variable: global;
}

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

¥Referencing Won't Modify Detached Ruleset Scope

规则集不会仅仅通过在此处被引用而获得对新作用域的访问权限:

¥A ruleset does not gain access to new scopes just by being referenced there:

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

抛出错误:

¥throws an error:

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

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

¥Unlocking Will Modify Detached Ruleset Scope

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

¥A detached ruleset gains access by being unlocked (imported) inside a scope:

#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();
}

编译成:

¥compiles into:

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

属性/变量访问器

¥Property / variable accessors

(查找值)

¥(Lookup values)

发布于 v3.5.0

¥Released v3.5.0

从 Less 3.5 开始,你可以使用属性/变量访问器(也称为 "lookups")从变量(分离的)规则集中选择一个值。

¥Starting in Less 3.5, you can use property/variable accessors (also called "lookups") to select a value from variable (detached) rulesets.

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

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

.box {
  .mixin();
}

输出:

¥Outputs:

.box {
  selected: value;
}

如果查找返回的是另一个分离的规则集,你可以使用第二个查找来获取该值。

¥If what is returned from a lookup is another detached ruleset, you can use a second lookup to get that value.

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

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

查找中的可变变量

¥Variable variables in lookups

返回的查找值本身可以是可变的。如在,你可以写:

¥The lookup value that is returned can itself be variable. As in, you can write:

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

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

这将输出:

¥This will output:

.box {
  color: darkblue;
}

映射

发布于 v3.5.0

¥Released v3.5.0

使用规则集和混合作为值映射

¥Use rulesets and mixins as maps of values

通过将命名空间与查找 [] 语法相结合,你可以将你的规则集/mixins 转换为映射。

¥By combining namespacing with the lookup [] syntax, you can turn your rulesets / mixins into maps.

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

.navbar {
  display: block;

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

输出:

¥Outputs:

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

由于命名空间和重载混入的能力,混入比映射更通用。

¥Mixins are a little more versatile as maps because of namespacing and the ability to overload mixins.

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

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

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

输出:

¥Outputs:

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

你也可以通过 混入别名 使这更容易。那是:

¥You can also make this easier by aliasing mixins. That is:

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

请注意,如果查找值生成另一个规则集,你可以附加第二个 [] 查找,如:

¥Note, if a lookup value produces another ruleset, you can append a second [] lookup, as in:

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

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

这样规则集和变量调用就可以模拟出 "namespacing" 的一种类型,类似于 mixins。

¥In this way, rulesets and variable calls can emulate a type of "namespacing", similar to mixins.

至于是否使用分配给变量的混合或规则集作为映射,由你决定。你可能希望通过重新声明分配给规则集的变量来替换整个映射。或者你可能想要 "merge" 个单独的键/值对,在这种情况下,混合作为映射可能更合适。

¥As far as whether to use mixins or rulesets assigned to variables as maps, it's up to you. You may want to replace entire maps by re-declaring a variable assigned to a rulset. Or you may want to "merge" individual key/value pairs, in which case mixins as maps might be more appropriate.

在查找中使用可变变量

¥Using variable variables in lookups

需要注意的一件重要事情是 [@lookup] 中的值是键(变量)名称 @lookup,并且未作为变量求值。如果希望键名本身是可变的,可以使用 @@variable 语法。

¥One important thing to notice is that the value in [@lookup] is the key (variable) name @lookup, and is not evaluated as a variable. If you want the key name itself to be variable, you can use the @@variable syntax.

例如。

¥E.g.

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

@key-to-lookup: dessert;

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

这将输出:

¥This would output:

.lunch {
  treat: ice cream;
}

作用域

Less 的一些额外的作用域特性

¥Some additional scoping features of Less

混入作用域特性

¥Mixin scope features

直观地,mixin 可以访问定义作用域。

¥Intuitively, mixins have access to definition scope.

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

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

弃用的混入作用域特性

¥Deprecated mixin scope features

这是可能在未来版本中删除的 mixin 作用域功能列表。

¥This is a list of mixin scope features that may be removed in future releases.

#1.(DEPRECATED)混入可以访问调用者作用域。

¥#1. (DEPRECATED) Mixins have access to caller scope.

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

这是违反直觉的,因为:

¥This is counter-intuitive because:

  1. 这在大多数其他语言中并不典型。

    ¥It is not typical in most other languages.

  2. 在查看定义时,mixin 将产生什么输出并不是很明显。

    ¥It's not immediately obvious when looking at the definition what output will be produced by the mixin.

首选方法:传入你希望对 mixin 可见的变量。

¥Preferred approach: Pass in the variable you want to be visible to the mixin.

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

#2.(DEPRECATED)调用者作用域可以访问混入中的变量

¥#2. (DEPRECATED) The caller scope has access to variables from the mixin

Mixins 会将它们的变量推送到调用者作用域,但前提是该变量未在本地定义。

¥Mixins will push their variables into the caller scope, but only if the variable is not locally defined.

#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;
}
*/

这是违反直觉的,因为:

¥This is counter-intuitive because:

  1. 调用者作用域中更高的变量可以被覆盖。

    ¥A variable higher in the caller scope can be overridden.

  2. 这也不是典型的语言行为。

    ¥It's also not a typical language behavior.

  3. 它不同于分离规则集的行为。

    ¥It differs from the behavior of detached rulesets.

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

¥Also, with the introduction of Maps, you can retrieve variable values (and mixins) directly.

首选方法:

¥Preferred approach:

#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.(DEPRECATED)调用者作用域可以从混入访问混入

¥#3. (DEPRECATED) The caller scope has access to mixins from the mixin

与弃用的变量行为类似,mixins 也被推入调用者作用域。然而,与变量不同的是,与合并作用域混入同名的混入被合并。

¥Similarly to deprecated variable behavior, mixins are also pushed into the caller scope. However, unlike variables, mixins with the same name as the merged scope mixin are merged.

#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;
}
*/

首选方法:直接调用 mixins。

¥Preferred approach: Call mixins directly.

#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;
}
*/

提示与技巧

¥Tips & Tricks

信用:less/less.js/issues/1472

¥Credit: less/less.js/issues/1472

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

¥Here is a trick for defining variables and keeping them in some private scope, preventing them from leaking to the global space.

& {
  // 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 仅为 & { ... } 创建的作用域定义。你还可以在规则中嵌套作用域:

¥Here, @height and @width are only defined for the scope created by & { ... } You can also nest an scope inside a rule:

.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 守卫

"if" 的周围选择器

¥"if"'s around selectors

发布于 v1.5.0

¥Released v1.5.0

与 Mixin Guards 一样,guards 也可以应用于 css 选择器,这是声明 mixin 然后立即调用它的语法糖。

¥Like Mixin Guards, guards can also be applied to css selectors, which is syntactic sugar for declaring the mixin and then calling it immediately.

例如,在 1.5.0 之前你必须这样做:

¥For instance, before 1.5.0 you would have had to do this:

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

现在,你可以将守卫直接应用于样式。

¥Now, you can apply the guard directly to a style.

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

你还可以通过将其与 & 功能相结合来实现 if 类型声明,从而允许你对多个守卫进行分组。

¥You can also achieve an if type statement by combining this with the & feature, allowing you to group multiple guards.

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

请注意,你还可以通过使用实际的 if() 函数和变量调用来实现类似的模式。如:

¥Note that you can also achieve a similar pattern by using the actual if() function and a variable call. As in:

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

@plugin 规则

发布于 v2.5.0

¥Released v2.5.0

导入 JavaScript 插件以添加 Less.js 功能和特性

¥Import JavaScript plugins to add Less.js functions and features

编写你的第一个插件

¥Writing your first plugin

使用 @plugin 规则类似于对 .less 文件使用 @import

¥Using a @plugin at-rule is similar to using an @import for your .less files.

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

由于 Less 插件在 Less 作用域内进行评估,因此插件定义可以非常简单。

¥Since Less plugins are evaluated within the Less scope, the plugin definition can be quite simple.

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

或者你可以使用 module.exports(可以在浏览器和 Node.js 中使用)。

¥or you can use module.exports (shimmed to work in browser as well as Node.js).

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

请注意,其他 Node.js CommonJS 约定(如 require())在浏览器中不可用。在编写跨平台插件时请记住这一点。

¥Note that other Node.js CommonJS conventions, like require() are not available in the browser. Keep this in mind when writing cross-platform plugins.

你可以使用插件做什么?很多,但让我们从基础开始。我们将首先关注你可能放入 install 函数中的内容。假设你这样写:

¥What can you do with a plugin? A lot, but let's start with the basics. We'll focus first on what you might put inside the install function. Let's say you write this:

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

恭喜!你写了一个 Less 插件!

¥Congratulations! You've written a Less plugin!

如果你要在样式表中使用它:

¥If you were to use this in your stylesheet:

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

你会得到:

¥You would get:

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

但是,如果你想将其与其他值相乘或执行其他 Less 操作,则需要返回一个正确的 Less 节点。否则样式表中的输出是纯文本(这可能适合你的目的)。

¥However, you would need to return a proper Less node if you wanted to, say, multiply that against other values or do other Less operations. Otherwise the output in your stylesheet is plain text (which may be fine for your purposes).

意思是,这是更正确的:

¥Meaning, this is more correct:

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

注意:维度是一个带或不带单位的数字,如 "10 像素",它将是 less.Dimension(10, "px")。有关单位列表,请参阅 Less API

¥Note: A dimension is a number with or without a unit, like "10px", which would be less.Dimension(10, "px"). For a list of units, see the Less API.

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

¥Now you can use your function in operations.

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

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

¥You may have noticed that there are available globals for your plugin file, namely a function registry (functions object), and the less object. These are there for convenience.

插件作用域

¥Plugin Scope

@plugin @ 规则添加的函数遵循 Less 作用域规则。这对于希望在不引入命名冲突的情况下添加功能的 Less 库作者来说非常有用。

¥Functions added by a @plugin at-rule adheres to Less scoping rules. This is great for Less library authors that want to add functionality without introducing naming conflicts.

例如,假设你有来自两个第三方库的 2 个插件,它们都有一个名为 "foo" 的函数。

¥For instance, say you have 2 plugins from two third-party libraries that both have a function named "foo".

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

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

没关系!你可以选择哪个库的函数创建哪个输出。

¥That's ok! You can choose which library's function creates which output.

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

这将产生:

¥This will produce:

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

对于共享插件的插件作者来说,这意味着你还可以通过将它们放在特定作用域内来有效地创建私有函数。就像这样,这将导致错误:

¥For plugin authors sharing their plugins, that means you can also effectively make private functions by placing them in a particular scope. As in, this will cause an error:

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

从 Less 3.0 开始,函数可以返回任何类型的 Node 类型,并且可以在任何级别调用。

¥As of Less 3.0, functions can return any kind of Node type, and can be called at any level.

这意味着,这会在 2.x 中引发错误,因为函数必须是属性值或变量赋值的一部分:

¥Meaning, this would throw an error in 2.x, as functions had to be part of the value of a property or variable assignment:

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

在 3.x 中,情况不再如此,函数可以返回 At-Rules、Rulesets、任何其他 Less 节点、字符串和数字(后两者被转换为 Anonymous 节点)。

¥In 3.x, that's no longer the case, and functions can return At-Rules, Rulesets, any other Less node, strings, and numbers (the latter two are converted to Anonymous nodes).

空函数

¥Null Functions

有时你可能想要调用一个函数,但你不想要任何输出(例如存储一个值供以后使用)。在这种情况下,你只需要从函数返回 false

¥There are times when you may want to call a function, but you don't want anything output (such as storing a value for later use). In that case, you just need to return false from the function.

var collection = [];

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

稍后你可以执行以下操作:

¥Later you could do something like:

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

Less.js 插件对象

¥The Less.js Plugin Object

Less.js 插件应该导出具有一个或多个这些属性的对象。

¥A Less.js plugin should export an object that has one or more of these properties.

{
    /* 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 实例提供了添加访问者、文件管理器和后处理器的方法。

¥The PluginManager instance for the install() function provides methods for adding visitors, file managers, and post-processors.

这里有一些示例 repos,显示了不同的插件类型。

¥Here are some example repos showing the different plugin types.

预加载插件

¥Pre-Loaded Plugins

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

¥While a @plugin call works well for most scenarios, there are times when you might want to load a plugin before parsing starts.

查阅:"使用 Less.js" 部分中的 预加载插件 介绍了如何做到这一点。

¥See: Pre-Loaded Plugins in the "Using Less.js" section for how to do that.