深入介绍 LESS 语言的功能。请参阅概述了解 Less 的简要概述。
有关安装和设置 Less 环境的深入指南以及有关使用 Less 进行开发的文档,请参阅:使用 Less.js。
深入介绍 LESS 语言的功能。请参阅概述了解 Less 的简要概述。
有关安装和设置 Less 环境的深入指南以及有关使用 Less 进行开发的文档,请参阅:使用 Less.js。
在单一位置控制常用的值。
看到相同的值重复几十次并不罕见甚至数百次在您的样式表中:
a,
.link {
color: #428bca;
}
.widget {
color: #fff;
background: #428bca;
}
变量可让您从单个位置控制这些值,从而使您的代码更易于维护:
// Variables
@link-color: #428bca; // sea blue
@link-color-hover: darken(@link-color, 10%);
// Usage
a,
.link {
color: @link-color;
}
a:hover {
color: @link-color-hover;
}
.widget {
color: #fff;
background: @link-color;
}
上面的例子主要集中于使用变量来控制CSS 规则中的值,但它们也可以在其他地方使用,例如选择器名称、属性名称、URL 和@import註釋。
v1.4.0
// Variables
@my-selector: banner;
// Usage
.@{my-selector} {
font-weight: bold;
line-height: 40px;
margin: 0 auto;
}
编译为:
.banner {
font-weight: bold;
line-height: 40px;
margin: 0 auto;
}
// Variables
@images: "../img";
// Usage
body {
color: #444;
background: url("@{images}/white-sand.png");
}
v1.4.0
句法:@import "@{themes}/tidal-wave.less";
请注意,在 v2.0.0 之前,仅考虑在根或当前范围内声明的变量,并且在查找变量时仅考虑当前文件和调用文件。
例子:
// Variables
@themes: "../../src/themes";
// Usage
@import "@{themes}/tidal-wave.less";
v1.6.0
@property: color;
.widget {
@{property}: #0ee;
background-@{property}: #999;
}
编译为:
.widget {
color: #0ee;
background-color: #999;
}
在 Less 中,您可以使用另一个变量定义一个变量的名称。
@primary: green;
@secondary: blue;
.section {
@color: primary;
.element {
color: @@color;
}
}
编译结果为:
.section .element {
color: green;
}
变量在使用前不必声明。
有效的 Less 代码片段:
.lazy-eval {
width: @var;
}
@var: @a;
@a: 9%;
这也是有效的:
.lazy-eval {
width: @var;
@a: 9%;
}
@var: @a;
@a: 100%;
都编译成:
.lazy-eval {
width: 9%;
}
当两次定义一个变量时,将使用该变量的最后一个定义,并从当前作用域向上搜索。这类似于 CSS 本身,使用定义中的最后一个属性来确定其值。
例如:
@var: 0;
.class {
@var: 1;
.brass {
@var: 2;
three: @var;
@var: 3;
}
one: @var;
}
编译为:
.class {
one: 1;
}
.class .brass {
three: 3;
}
本质上,每个范围都有一个“最终”值,类似于浏览器中的属性,就像这个使用自定义属性的例子:
.header {
--color: white;
color: var(--color); // the color is black
--color: black;
}
这意味着,与其他 CSS 预处理语言不同,Less 变量的行为非常类似于 CSS。
v3.0.0
您可以使用以下方式轻松地将属性视为变量$prop语法。有时这可以使您的代码更轻量。
.widget {
color: #efefef;
background-color: $color;
}
编译为:
.widget {
color: #efefef;
background-color: #efefef;
}
请注意,与变量一样,Less 将选择当前/父范围内的最后一个属性作为“最终”值。
.block {
color: red;
.inner {
background-color: $color;
}
color: blue;
}
编译为:
.block {
color: red;
color: blue;
}
.block .inner {
background-color: blue;
}
我们有时会收到关于默认变量的请求——即仅在变量尚未设置时才设置该变量的功能。此功能并非必需,因为您可以通过事后添加定义来轻松覆盖变量。
例如:
// library
@base-color: green;
@dark-color: darken(@base-color, 10%);
// use of library
@import "library.less";
@base-color: red;
这很好,因为延迟加载-@base-color被覆盖,并且@dark-color呈深红色。
引用父选择器
&
这&运算符表示嵌套规则最常用于将修改类或伪类应用于现有选择器时:
a {
color: blue;
&:hover {
color: green;
}
}
结果为:
a {
color: blue;
}
a:hover {
color: green;
}
请注意,如果没有&,上述示例将导致a :hover规则(匹配悬停元素的后代选择器<a>标签)这通常不是我们想要的嵌套:hover。
“父选择器”运算符有多种用途。基本上,当你需要以非默认方式组合嵌套规则的选择器时,可以使用它。例如,另一个典型的用法是&就是产生重复的类名:
.button {
&-ok {
background-image: url("ok.png");
}
&-cancel {
background-image: url("cancel.png");
}
&-custom {
background-image: url("custom.png");
}
}
输出:
.button-ok {
background-image: url("ok.png");
}
.button-cancel {
background-image: url("cancel.png");
}
.button-custom {
background-image: url("custom.png");
}
&&可以在一个选择器中出现多次。这样就可以重复引用父选择器,而无需重复其名称。
.link {
& + & {
color: red;
}
& & {
color: green;
}
&& {
color: blue;
}
&, &ish {
color: cyan;
}
}
将输出:
.link + .link {
color: red;
}
.link .link {
color: green;
}
.link.link {
color: blue;
}
.link, .linkish {
color: cyan;
}
注意&表示所有父选择器(不仅仅是最近的祖先),因此以下示例:
.grand {
.parent {
& > & {
color: red;
}
& & {
color: green;
}
&& {
color: blue;
}
&, &ish {
color: cyan;
}
}
}
结果为:
.grand .parent > .grand .parent {
color: red;
}
.grand .parent .grand .parent {
color: green;
}
.grand .parent.grand .parent {
color: blue;
}
.grand .parent,
.grand .parentish {
color: cyan;
}
将选择器添加到继承的(父)选择器中会很有用。这可以通过将&在当前选择器之后。例如,使用 Modernizr 时,你可能希望根据支持的功能指定不同的规则:
.header {
.menu {
border-radius: 5px;
.no-borderradius & {
background-image: url('images/button-background.png');
}
}
}
选择器.no-borderradius &将会添加.no-borderradius到它的父母.header .menu形成.no-borderradius .header .menu输出:
.header .menu {
border-radius: 5px;
}
.no-borderradius .header .menu {
background-image: url('images/button-background.png');
}
&还可以用于生成以逗号分隔的列表中选择器的所有可能排列:
p, a, ul, li {
border-top: 2px dotted #366;
& + & {
border-top: 0;
}
}
扩展为指定元素的所有可能(16)种组合:
p,
a,
ul,
li {
border-top: 2px dotted #366;
}
p + p,
p + a,
p + ul,
p + li,
a + p,
a + a,
a + ul,
a + li,
ul + p,
ul + a,
ul + ul,
ul + li,
li + p,
li + a,
li + ul,
li + li {
border-top: 0;
}
从其他样式表导入样式
在标准 CSS 中,@import@ 规则必须位于所有其他类型的规则之前。但 Less 并不关心你把 @ 规则放在哪里@import註釋。
例子:
.foo {
background: #900;
}
@import "this-is-valid.less";
@importLess 可能会根据文件扩展名对语句进行不同的处理:
.css扩展它将被视为 CSS 和@import声明保持原样(参见内联选项以下)。.less将被附加并作为导入的 Less 文件包含在内。例子:
@import "foo"; // foo.less is imported
@import "foo.less"; // foo.less is imported
@import "foo.php"; // foo.php imported as a Less file
@import "foo.css"; // statement left in place, as-is
可以使用以下选项来覆盖此行为。
Less 为 CSS 提供了多种扩展
@importCSS at-rule 为您处理外部文件提供了更多的灵活性。
句法:@import (keyword) "filename";
已实施以下导入选项:
reference:使用 Less 文件但不输出它inline:在输出中包含源文件但不对其进行处理less:将文件视为 Less 文件,无论文件扩展名是什么css:将文件视为 CSS 文件,无论文件扩展名是什么once:仅包含文件一次(这是默认行为)multiple:多次包含该文件optional:找不到文件时继续编译每个超过一个关键字
@import是允许的,您必须使用逗号分隔关键字:
例子:@import (optional, reference) "foo.less";
使用@import (reference)导入外部文件,但除非引用,否则不会将导入的样式添加到编译的输出中。
发布v1.5.0
例子:@import (reference) "foo.less";
想象一下reference用参考标志在导入的文件中,导入正常,但在生成 CSS 时,“引用”选择器(以及任何仅包含引用选择器的媒体查询)不会输出。reference样式不会显示在生成的 CSS 中,除非引用样式被用作混合或者延长。
此外,reference根据所使用的方法(mixin 或 extends)产生不同的结果:
这样您就可以从库中提取特定的、有针对性的样式,例如引导程序通过做这样的事情:
.navbar:extend(.navbar all) {}
你只会拉.navbar来自 Bootstrap 的相关样式。
使用@import (inline)包含外部文件,但不处理它们。
发布v1.5.0
例子:@import (inline) "not-less-compatible.css";
当 CSS 文件可能与 Less 不兼容时,您将使用它;这是因为尽管 Less 支持大多数已知标准 CSS,但它在某些地方不支持注释,并且不支持所有已知的 CSS hack(无需修改 CSS)。
因此您可以使用它将文件包含在输出中,以便所有 CSS 都位于一个文件中。
使用@import (less)将导入的文件视为 Less 文件,无论文件扩展名是什么。
发布v1.4.0
例子:
@import (less) "foo.css";
使用@import (css)将导入的文件视为常规 CSS,无论文件扩展名是什么。这意味着 import 语句将保持原样。
发布v1.4.0
例子:
@import (css) "foo.less";
输出
@import "foo.less";
默认行为@import语句。这意味着该文件仅被导入一次,并且该文件的后续导入语句将被忽略。
发布v1.4.0
这是@import註釋。
例子:
@import (once) "foo.less";
@import (once) "foo.less"; // this statement will be ignored
使用@import (multiple)允许导入多个同名文件。这与 once 的行为相反。
发布v1.4.0
例子:
// file: foo.less
.a {
color: green;
}
// file: main.less
@import (multiple) "foo.less";
@import (multiple) "foo.less";
输出
.a {
color: green;
}
.a {
color: green;
}
使用@import (optional)仅当文件存在时才允许导入。如果没有optional当导入无法找到的文件时,关键字 Less 会抛出 FileError 并停止编译。
发布v2.3.0
Extend 是一个 Less 伪类,它将所放置的选择器与与其引用匹配的选择器合并。
发布v1.4.0
nav ul {
&:extend(.inline);
background: blue;
}
在上述规则中,:extend选择器将应用“扩展选择器”(nav ul)到.inline班级无论.inline类出现。声明块将保持原样,但不引用任何扩展(因为扩展不是 css)。
因此如下:
nav ul {
&:extend(.inline);
background: blue;
}
.inline {
color: red;
}
输出
nav ul {
background: blue;
}
.inline,
nav ul {
color: red;
}
注意nav ul:extend(.inline)选择器获得输出为nav ul- 扩展在输出前被移除,选择器块保持原样。如果该块中未添加任何属性,则会从输出中移除(但扩展仍可能影响其他选择器)。
扩展可以附加到选择器,也可以放入规则集中。它看起来像一个伪类,带有可选的选择器参数,后面跟着关键字all:
例子:
.a:extend(.b) {}
// the above block does the same thing as the below block
.a {
&:extend(.b);
}
.c:extend(.d all) {
// extends all instances of ".d" e.g. ".x.d" or ".d.x"
}
.c:extend(.d) {
// extends only instances where the selector will be output as just ".d"
}
它可以包含一个或多个要扩展的类,以逗号分隔。
例子:
.e:extend(.f) {}
.e:extend(.g) {}
// the above and the below do the same thing
.e:extend(.f, .g) {}
附加到选择器上的扩展看起来就像一个带有选择器作为参数的普通伪类。一个选择器可以包含多个扩展子句,但所有扩展都必须位于选择器的末尾。
pre:hover:extend(div pre)。pre:hover :extend(div pre)。pre:hover:extend(div pre):extend(.bucket tr)- 注意,这与pre:hover:extend(div pre, .bucket tr)pre:hover:extend(div pre).nth-child(odd). 延伸必须是最后。如果规则集包含多个选择器,则其中任何一个都可以包含extend关键字。一个规则集中包含多个带有extend关键字的选择器:
.big-division,
.big-bag:extend(.bag),
.big-bucket:extend(.bucket) {
// body
}
可以使用以下方式将扩展放入规则集主体中&:extend(selector)语法。将扩展放入主体中是将其放入该规则集的每个选择器中的快捷方式。
在主体内部延伸:
pre:hover,
.some-class {
&:extend(div pre);
}
与每个选择器后添加扩展完全相同:
pre:hover:extend(div pre),
.some-class:extend(div pre) {}
Extend 能够匹配嵌套选择器。以下是 less 的用法:
例子:
.bucket {
tr { // nested ruleset with target selector
color: blue;
}
}
.some-class:extend(.bucket tr) {} // nested ruleset is recognized
输出
.bucket tr,
.some-class {
color: blue;
}
本质上,extend 查看的是编译后的 css,而不是原始的 css。
例子:
.bucket {
tr & { // nested ruleset with target selector
color: blue;
}
}
.some-class:extend(tr .bucket) {} // nested ruleset is recognized
输出
tr .bucket,
.some-class {
color: blue;
}
默认情况下,Extend 会在选择器之间查找精确匹配。选择器是否使用星号开头并不重要。两个第 n 个表达式的含义是否相同并不重要,它们需要具有相同的形式才能匹配。唯一的例外是属性选择器中的引号,因为 Less 知道它们具有相同的含义并进行匹配。
例子:
.a.class,
.class.a,
.class > .a {
color: blue;
}
.test:extend(.class) {} // this will NOT match the any selectors above
领衔明星确实很重要。选择者*.class和.class是等效的,但是扩展不会匹配它们:
*.class {
color: blue;
}
.noStar:extend(.class) {} // this will NOT match the *.class selector
输出
*.class {
color: blue;
}
伪类的顺序确实很重要。选择器link:hover:visited和link:visited:hover匹配同一组元素,但扩展将它们视为不同的元素:
link:hover:visited {
color: blue;
}
.selector:extend(link:visited:hover) {}
输出
link:hover:visited {
color: blue;
}
第 N 个表达式形式确实很重要。第 N 个表达式1n+3和n+3是等效的,但是扩展不会匹配它们:
:nth-child(1n+3) {
color: blue;
}
.child:extend(:nth-child(n+3)) {}
输出
:nth-child(1n+3) {
color: blue;
}
属性选择器中的引号类型无关紧要。以下所有内容均等效。
[title=identifier] {
color: blue;
}
[title='identifier'] {
color: blue;
}
[title="identifier"] {
color: blue;
}
.noQuote:extend([title=identifier]) {}
.singleQuote:extend([title='identifier']) {}
.doubleQuote:extend([title="identifier"]) {}
输出
[title=identifier],
.noQuote,
.singleQuote,
.doubleQuote {
color: blue;
}
[title='identifier'],
.noQuote,
.singleQuote,
.doubleQuote {
color: blue;
}
[title="identifier"],
.noQuote,
.singleQuote,
.doubleQuote {
color: blue;
}
当你在扩展参数的最后指定 all 关键字时,它会告诉 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} { // interpolated selector
color: blue;
}
.some-class:extend(.bucket) {} // does nothing, no match is found
并使用目标选择器中的变量进行扩展,但没有任何匹配:
.bucket {
color: blue;
}
.some-class:extend(@{variable}) {} // interpolated selector matches nothing
@variable: .bucket;
上述两个示例编译后为:
.bucket {
color: blue;
}
然而,:extend附加到插值选择器的工作原理:
.bucket {
color: blue;
}
@{variable}:extend(.bucket) {}
@variable: .selector;
编译为:
.bucket, .selector {
color: blue;
}
目前,:extend在里面@media声明将仅与同一媒体声明内的选择器匹配:
@media print {
.screenClass:extend(.selector) {} // extend inside media
.selector { // this will be matched - it is in the same media
color: black;
}
}
.selector { // ruleset on top of style sheet - extend ignores it
color: red;
}
@media screen {
.selector { // ruleset inside another media - extend ignores it
color: blue;
}
}
编译为:
@media print {
.selector,
.screenClass { /* ruleset inside the same media was extended */
color: black;
}
}
.selector { /* ruleset on top of style sheet was ignored */
color: red;
}
@media screen {
.selector { /* ruleset inside another media was ignored */
color: blue;
}
}
注意:扩展与嵌套内部的选择器不匹配@media宣言:
@media screen {
.screenClass:extend(.selector) {} // extend inside media
@media (min-width: 1023px) {
.selector { // ruleset inside nested media - extend ignores it
color: blue;
}
}
}
编译结果如下:
@media screen and (min-width: 1023px) {
.selector { /* ruleset inside another nested media was ignored */
color: blue;
}
}
顶级扩展匹配所有内容,包括嵌套媒体内的选择器:
@media screen {
.selector { /* ruleset inside nested media - top level extend works */
color: blue;
}
@media (min-width: 1023px) {
.selector { /* ruleset inside nested media - top level extend works */
color: blue;
}
}
}
.topLevel:extend(.selector) {} /* top level extend matches everything */
编译为:
@media screen {
.selector,
.topLevel { /* ruleset inside media was extended */
color: blue;
}
}
@media screen and (min-width: 1023px) {
.selector,
.topLevel { /* ruleset inside nested media was extended */
color: blue;
}
}
目前没有重复检测。
例子:
.alert-info,
.widget {
/* declarations */
}
.alert:extend(.alert-info, .widget) {}
输出
.alert-info,
.widget,
.alert,
.alert {
/* declarations */
}
典型的用例是避免添加基类。例如,如果你有
.animal {
background-color: black;
color: white;
}
并且你想要一个动物子类型来覆盖背景颜色,那么你有两个选择,首先改变你的 HTML
<a class="animal bear">Bear</a>
.animal {
background-color: black;
color: white;
}
.bear {
background-color: brown;
}
或者简化 html 并在 less 中使用扩展。例如
<a class="bear">Bear</a>
.animal {
background-color: black;
color: white;
}
.bear {
&:extend(.animal);
background-color: brown;
}
Mixins 会将所有属性复制到选择器中,这可能会导致不必要的重复。因此,您可以使用 extends 代替 mixins,将选择器上移至您想要使用的属性,从而减少生成的 CSS。
示例 - 使用 mixin:
.my-inline-block() {
display: inline-block;
font-size: 0;
}
.thing1 {
.my-inline-block;
}
.thing2 {
.my-inline-block;
}
输出
.thing1 {
display: inline-block;
font-size: 0;
}
.thing2 {
display: inline-block;
font-size: 0;
}
示例(带有扩展):
.my-inline-block {
display: inline-block;
font-size: 0;
}
.thing1 {
&:extend(.my-inline-block);
}
.thing2 {
&:extend(.my-inline-block);
}
输出
.my-inline-block,
.thing1,
.thing2 {
display: inline-block;
font-size: 0;
}
另一个用例是作为 mixin 的替代品 - 因为 mixin 只能与简单选择器一起使用,如果您有两个不同的 html 块,但需要对两者应用相同的样式,则可以使用 extends 来关联两个区域。
例子:
li.list > a {
// list styles
}
button.list-style {
&:extend(li.list > a); // use the same list styles
}
合并属性
这merge该功能允许将多个属性的值聚合到单个属性下的逗号或空格分隔的列表中。merge对于背景和变换等属性很有用。
用逗号附加属性值
发布v1.5.0
例子:
.mixin() {
box-shadow+: inset 0 0 10px #555;
}
.myclass {
.mixin();
box-shadow+: 0 0 20px black;
}
输出
.myclass {
box-shadow: inset 0 0 10px #555, 0 0 20px black;
}
用空格附加属性值
发布v1.7.0
例子:
.mixin() {
transform+_: scale(2);
}
.myclass {
.mixin();
transform+_: rotate(15deg);
}
输出
.myclass {
transform: scale(2) rotate(15deg);
}
为了避免任何意外的连接,merge需要明确的+或者+_每个连接待决声明上的标志。
来自现有样式的“混合”属性
你可以混合使用类选择器和 ID 选择器,例如
.a, #b {
color: red;
}
.mixin-class {
.a();
}
.mixin-id {
#b();
}
其结果是:
.a, #b {
color: red;
}
.mixin-class {
color: red;
}
.mixin-id {
color: red;
}
从历史上看,mixin 调用中的括号是可选的,但可选括号已被弃用,并且在未来的版本中将是必需的。
.a();
.a; // currently works, but deprecated; don't use
.a (); // white-space before parentheses is also deprecated
如果您想创建一个 mixin,但不希望该 mixin 出现在您的 CSS 输出中,请在 mixin 定义后加上括号。
.my-mixin {
color: black;
}
.my-other-mixin() {
background: white;
}
.class {
.my-mixin();
.my-other-mixin();
}
输出
.my-mixin {
color: black;
}
.class {
color: black;
background: white;
}
Mixins 不仅可以包含属性,还可以包含选择器。
例如:
.my-hover-mixin() {
&:hover {
border: 1px solid red;
}
}
button {
.my-hover-mixin();
}
输出
button:hover {
border: 1px solid red;
}
如果您想在更复杂的选择器中混合属性,您可以堆叠多个 ID 或类。
#outer() {
.inner {
color: red;
}
}
.c {
#outer.inner();
}
注意:旧版 Less 语法允许>以及命名空间和混合宏之间的空格。此语法已弃用,可能会被移除。目前,它们的作用相同。
#outer > .inner(); // deprecated
#outer .inner(); // deprecated
#outer.inner(); // preferred
像这样对 mixin 进行命名空间可以减少与其他库 mixin 或用户 mixin 的冲突,但也可以成为“组织” mixin 组的一种方式。
例子:
#my-library {
.my-mixin() {
color: black;
}
}
// which can be used like this
.class {
#my-library.my-mixin();
}
如果命名空间有守卫,则仅当守卫条件返回 true 时,才会使用由该守卫定义的混合宏。命名空间守卫的执行方式与混合宏上的守卫完全相同,因此以下两个混合宏的工作方式相同:
#namespace when (@mode = huge) {
.mixin() { /* */ }
}
#namespace {
.mixin() when (@mode = huge) { /* */ }
}
这default函数被假定对所有嵌套命名空间和混合宏都具有相同的值。以下混合宏永远不会被求值;它的一个保护函数必然为 false:
#sp_1 when (default()) {
#sp_2 when (default()) {
.mixin() when not(default()) { /* */ }
}
}
!important关键词使用!importantmixin 调用后的关键字,将其继承的所有属性标记为!important:
例子:
.foo (@bg: #f5f5f5, @color: #900) {
background: @bg;
color: @color;
}
.unimportant {
.foo();
}
.important {
.foo() !important;
}
结果:
.unimportant {
background: #f5f5f5;
color: #900;
}
.important {
background: #f5f5f5 !important;
color: #900 !important;
}
如何向 mixins 传递参数
Mixins 还可以接受参数,这些参数是在混合时传递给选择器块的变量。
例如:
.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).name(1, 2, 3;)。注意:如果结尾的分号看起来很奇怪,您可能更喜欢:.name(~(1, 2, 3))@param-values: red, blue; .name(@param1: @param-values)。.name(@param1: red, blue;).name(@param1: ~(red, blue))定义多个具有相同名称和参数数量的 mixin 是合法的。Less 会使用所有适用的属性。例如,如果你使用了一个只有一个参数的 mixin,.mixin(green);,则将使用具有一个强制参数的所有 mixin 的属性:
.mixin(@color) {
color-1: @color;
}
.mixin(@color, @padding: 2) {
color-2: @color;
padding-2: @padding;
}
.mixin(@color, @padding, @margin: 2) {
color-3: @color;
padding-3: @padding;
margin: @margin @margin @margin @margin;
}
.some .selector div {
.mixin(#008000);
}
编译为:
.some .selector div {
color-1: #008000;
color-2: #008000;
padding-2: 2;
}
mixin 引用可以通过参数名称而非位置来提供参数值。任何参数都可以通过其名称引用,并且无需遵循任何特殊顺序:
.mixin(@color: black; @margin: 10px; @padding: 20px) {
color: @color;
margin: @margin;
padding: @padding;
}
.class1 {
.mixin(@margin: 20px; @color: #33acfe);
}
.class2 {
.mixin(#efca44; @padding: 40px);
}
编译为:
.class1 {
color: #33acfe;
margin: 20px;
padding: 20px;
}
.class2 {
color: #efca44;
margin: 10px;
padding: 40px;
}
@arguments多变的@arguments在mixin中具有特殊含义,它包含了调用mixin时传递的所有参数。如果你不想处理单个参数,这很有用:
.box-shadow(@x: 0, @y: 0, @blur: 1px, @color: #000) {
-webkit-box-shadow: @arguments;
-moz-box-shadow: @arguments;
box-shadow: @arguments;
}
.big-block {
.box-shadow(2px, 5px);
}
其结果是:
.big-block {
-webkit-box-shadow: 2px 5px 1px #000;
-moz-box-shadow: 2px 5px 1px #000;
box-shadow: 2px 5px 1px #000;
}
@rest多变的您可以使用...如果你想让你的 mixin 接受可变数量的参数,在变量名后使用这个选项会将这些参数赋值给变量。
.mixin(...) { // matches 0-N arguments
.mixin() { // matches exactly 0 arguments
.mixin(@a: 1) { // matches 0-1 arguments
.mixin(@a: 1, ...) { // matches 0-N arguments
.mixin(@a, ...) { // matches 1-N arguments
此外:
.mixin(@a, @rest...) {
// @rest is bound to arguments after @a
// @arguments is bound to all arguments
}
有时,你可能想根据传递给它的参数来改变mixin的行为。让我们从一些基本的东西开始:
.mixin(@s, @color) { ... }
.class {
.mixin(@switch, #888);
}
现在假设我们想要.mixin根据价值采取不同的行为@switch,我们可以定义.mixin像这样:
.mixin(dark, @color) {
color: darken(@color, 10%);
}
.mixin(light, @color) {
color: lighten(@color, 10%);
}
.mixin(@_, @color) {
display: block;
}
现在,如果我们运行:
@switch: light;
.class {
.mixin(@switch, #888);
}
我们将得到以下 CSS:
.class {
color: #a2a2a2;
display: block;
}
颜色传递到哪里.mixin被点亮了。如果@switch曾是dark,结果颜色会更暗。
事情是这样的:
dark作为第一个参数。light。仅使用匹配的 mixin 定义。变量匹配并绑定到任何值。除变量之外的任何值仅与等于其自身的值匹配。
我们还可以根据元数进行匹配,以下是示例:
.mixin(@a) {
color: @a;
}
.mixin(@a, @b) {
color: fade(@a, @b);
}
现在如果我们调用.mixin使用单个参数,我们将获得第一个定义的输出,但如果我们用二参数,我们将得到第二个定义,即@a淡出为@b。
从 mixin 调用中选择属性和变量
发布v3.5.0
从 Less 3.5 开始,您可以使用属性/变量访问器从已评估的 mixin 规则中选择一个值。这允许您像使用函数一样使用 mixin。
例子:
.average(@x, @y) {
@result: ((@x + @y) / 2);
}
div {
// call a mixin and look up its "@result" value
padding: .average(16px, 50px)[@result];
}
结果:
div {
padding: 33px;
}
如果有多个匹配的 mixin,则会评估并合并所有规则,并返回最后一个与该标识符匹配的值。这类似于 CSS 中的级联,它允许您“覆盖” mixin 的值。
// library.less
#library() {
.mixin() {
prop: foo;
}
}
// customize.less
@import "library";
#library() {
.mixin() {
prop: bar;
}
}
.box {
my-value: #library.mixin[prop];
}
输出:
.box {
my-value: bar;
}
如果您没有在[@lookup]而是写[]在 mixin 或规则集调用之后,全部值将级联并选择最后声明的值。
含义:上述示例中的平均混合可以写成:
.average(@x, @y) {
@result: ((@x + @y) / 2);
}
div {
// call a mixin and look up its final value
padding: .average(16px, 50px)[];
}
输出是一样的:
div {
padding: 33px;
}
对于别名为 mixin 调用的规则集或变量,相同的级联行为也适用。
@dr: {
value: foo;
}
.box {
my-value: @dr[];
}
输出:
.box {
my-value: foo;
}
已弃用 - 使用属性/值访问器
在 mixin 中定义的变量和 mixin 在调用方作用域内可见,并可用。只有一种例外:如果调用方包含同名变量(包含由另一个 mixin 调用定义的变量),则变量不会被复制。只有调用方本地作用域中的变量才受保护。从父作用域继承的变量会被覆盖。
注意:此行为已被弃用,将来,变量和混合将不会以这种方式合并到调用者范围中。
例子:
.mixin() {
@width: 100%;
@height: 200px;
}
.caller {
.mixin();
width: @width;
height: @height;
}
结果:
.caller {
width: 100%;
height: 200px;
}
直接在调用方作用域中定义的变量无法被覆盖。但是,在调用方父级作用域中定义的变量不受保护,因此会被覆盖:
.mixin() {
@size: in-mixin;
@definedOnlyInMixin: in-mixin;
}
.class {
margin: @size @definedOnlyInMixin;
.mixin();
}
@size: globaly-defined-value; // callers parent scope - no protection
结果:
.class {
margin: in-mixin in-mixin;
}
最后,mixin 中定义的 mixin 也作为返回值:
.unlock(@value) { // outer mixin
.doSomething() { // nested mixin
declaration: @value;
}
}
#namespace {
.unlock(5); // unlock doSomething mixin
.doSomething(); //nested mixin was copied here and is usable
}
结果:
#namespace {
declaration: 5;
}
创建循环
在 Less 中,mixin 可以调用自身。这种递归 mixin 与保护表达式和模式匹配,可用于创建各种迭代/循环结构。
例子:
.loop(@counter) when (@counter > 0) {
.loop((@counter - 1)); // next iteration
width: (10px * @counter); // code for each iteration
}
div {
.loop(5); // launch the loop
}
输出:
div {
width: 10px;
width: 20px;
width: 30px;
width: 40px;
width: 50px;
}
使用递归循环生成 CSS 网格类的通用示例:
.generate-columns(4);
.generate-columns(@n, @i: 1) when (@i =< @n) {
.column-@{i} {
width: (@i * 100% / @n);
}
.generate-columns(@n, (@i + 1));
}
输出:
.column-1 {
width: 25%;
}
.column-2 {
width: 50%;
}
.column-3 {
width: 75%;
}
.column-4 {
width: 100%;
}
当你想匹配时,守卫很有用表达式,而不是简单的值或元数。如果你熟悉函数式编程,你可能已经遇到过它们了。
为了尽可能地保持 CSS 的声明性,Less 选择通过以下方式实现条件执行:受保护的混合而不是if/else声明,类似于@media查询特征规格。
让我们从一个例子开始:
.mixin(@a) when (lightness(@a) >= 50%) {
background-color: black;
}
.mixin(@a) when (lightness(@a) < 50%) {
background-color: white;
}
.mixin(@a) {
color: @a;
}
关键是when关键字,它引入了一个保护序列(这里只有一个保护)。现在,如果我们运行以下代码:
.class1 { .mixin(#ddd) }
.class2 { .mixin(#555) }
我们将得到以下结果:
.class1 {
background-color: black;
color: #ddd;
}
.class2 {
background-color: white;
color: #555;
}
保护中可用的比较运算符的完整列表如下:>,>=,=,=<,<。此外,关键字true是唯一的真值,使得这两个混合宏等效:
.truth(@a) when (@a) { ... }
.truth(@a) when (@a = true) { ... }
除关键字之外的任何值true是假的:
.class {
.truth(40); // Will not match any of the above definitions.
}
请注意,您还可以将参数相互比较,或与非参数进行比较:
@media: mobile;
.mixin(@a) when (@media = mobile) { ... }
.mixin(@a) when (@media = desktop) { ... }
.max(@a; @b) when (@a > @b) { width: @a }
.max(@a; @b) when (@a < @b) { width: @b }
您可以将逻辑运算符与保护语句一起使用。语法基于 CSS 媒体查询。
使用and组合防护装置的关键字:
.mixin(@a) when (isnumber(@a)) and (@a > 0) { ... }
你可以模仿或者用逗号分隔守卫的操作员,. 如果任何一个守卫的评估结果为真,则认为匹配:
.mixin(@a) when (@a > 10), (@a < -10) { ... }
使用not否定条件的关键字:
.mixin(@b) when not (@b > 0) { ... }
最后,如果你想根据值类型匹配 mixin,你可以使用is功能:
.mixin(@a; @b: 0) when (isnumber(@b)) { ... }
.mixin(@a; @b: black) when (iscolor(@b)) { ... }
以下是基本类型检查函数:
iscolorisnumberisstringiskeywordisurl如果您想要检查某个值除了是数字之外是否还具有特定的单位,则可以使用以下方法之一:
ispixelispercentageisemisunit发布v3.5.0
将 mixin 调用赋值给变量
Mixins可以赋值给变量作为变量调用,也可以用于地图查找。
#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;
}
整个 mixin 调用可以设置别名,并以变量调用的方式进行调用。例如:
#library() {
.colors() {
background: green;
}
}
.box {
@alias: #library.colors();
@alias();
}
输出:
.box {
background: green;
}
注意,与 root 中使用的 mixin 不同,mixin 调用分配给变量和不带参数调用始终需要括号。以下代码无效。
#library() {
.colors() {
background: green;
}
}
.box {
@alias: #library.colors;
@alias(); // ERROR: Could not evaluate variable call @alias
}
这是因为,如果将变量赋值为选择器列表或 mixin 调用,则会产生歧义。例如,在 Less 3.5+ 版本中,这个变量可以这样使用。
.box {
@alias: #library.colors;
@{alias} {
a: b;
}
}
以上将输出:
.box #library.colors {
a: b;
}
将规则集分配给变量
发布v1.7.0
分离规则集是一组 CSS 属性、嵌套规则集、媒体声明或其他存储在变量中的元素。您可以将其包含到规则集或其他结构中,其所有属性都会被复制到那里。您也可以将其用作 mixin 参数,并将其作为任何其他变量传递。
简单示例:
// declare detached ruleset
@detached-ruleset: { background: red; }; // semi-colon is optional in 3.5.0+
// use detached ruleset
.top {
@detached-ruleset();
}
编译为:
.top {
background: red;
}
分离规则集调用后的括号是必需的(除非后面跟着查找值)调用@detached-ruleset;不会起作用。
当你想要定义一个 mixin 来抽象出将一段代码包装在媒体查询中或不受支持的浏览器类名中时,它非常有用。规则集可以传递给 mixin,以便 mixin 能够包装内容,例如
.desktop-and-old-ie(@rules) {
@media screen and (min-width: 1200px) { @rules(); }
html.lt-ie9 & { @rules(); }
}
header {
background-color: blue;
.desktop-and-old-ie({
background-color: red;
});
}
这里desktop-and-old-iemixin 定义了媒体查询和根类,以便你可以使用 mixin 来包装一段代码。这将输出
header {
background-color: blue;
}
@media screen and (min-width: 1200px) {
header {
background-color: red;
}
}
html.lt-ie9 header {
background-color: red;
}
现在可以将规则集分配给变量或传递给 mixin,并且可以包含全套 Less 功能,例如
@my-ruleset: {
.my-selector {
background-color: black;
}
};
你甚至可以利用媒体查询冒泡, 例如
@my-ruleset: {
.my-selector {
@media tv {
background-color: black;
}
}
};
@media (orientation:portrait) {
@my-ruleset();
}
这将输出
@media (orientation: portrait) and tv {
.my-selector {
background-color: black;
}
}
分离规则集调用会像 mixin 调用一样,将其所有 mixin 解锁(返回)给调用者。然而,它不是返回变量。
返回的混合:
// detached ruleset with a mixin
@detached-ruleset: {
.mixin() {
color: blue;
}
};
// call detached ruleset
.caller {
@detached-ruleset();
.mixin();
}
结果:
.caller {
color: blue;
}
私有变量:
@detached-ruleset: {
@color:blue; // this variable is private
};
.caller {
color: @color; // syntax error
}
分离规则集可以使用所有可访问的变量和混合定义以及它在哪里称为换句话说,定义作用域和调用者作用域均对其可用。如果两个作用域包含相同的变量或混合宏,则声明作用域的值优先。
声明范围是定义分离规则集主体的地方。将分离规则集从一个变量复制到另一个变量并不能修改其作用域。规则集不能仅仅通过引用新的作用域来访问新的作用域。
最后,分离的规则集可以通过解锁(导入)来访问范围。
注意:通过调用 mixin 将变量解锁到作用域中的做法已被弃用。使用属性/变量访问器。
分离的规则集可以看到调用者的变量和混合:
@detached-ruleset: {
caller-variable: @caller-variable; // variable is undefined here
.caller-mixin(); // mixin is undefined here
};
selector {
// use detached ruleset
@detached-ruleset();
// define variable and mixin needed inside the detached ruleset
@caller-variable: value;
.caller-mixin() {
variable: declaration;
}
}
编译为:
selector {
caller-variable: value;
variable: declaration;
}
从定义中访问的变量和混合优于调用者中可用的变量和混合:
@variable: global;
@detached-ruleset: {
// will use global variable, because it is accessible
// from detached-ruleset definition
variable: @variable;
};
selector {
@detached-ruleset();
@variable: value; // variable defined in caller - will be ignored
}
编译为:
selector {
variable: global;
}
规则集不能仅通过被引用来获得对新范围的访问权限:
@detached-1: { scope-detached: @one @two; };
.one {
@one: visible;
.two {
@detached-2: @detached-1; // copying/renaming ruleset
@two: visible; // ruleset can not see this variable
}
}
.use-place {
.one > .two();
@detached-2();
}
引发错误:
ERROR 1:32 The variable "@one" was not declared.
分离的规则集通过在范围内解锁(导入)来获得访问权限:
#space {
.importer-1() {
@detached: { scope-detached: @variable; }; // define detached ruleset
}
}
.importer-2() {
@variable: value; // unlocked detached ruleset CAN see this variable
#space > .importer-1(); // unlock/import detached ruleset
}
.use-place {
.importer-2(); // unlock/import detached ruleset second time
@detached();
}
编译为:
.use-place {
scope-detached: value;
}
发布v3.5.0
从 Less 3.5 开始,您可以使用属性/变量访问器(也称为“查找”)从变量(分离)规则集中选择一个值。
@config: {
option1: true;
option2: false;
}
.mixin() when (@config[option1] = true) {
selected: value;
}
.box {
.mixin();
}
输出:
.box {
selected: value;
}
如果查找返回的是另一个分离的规则集,则可以使用第二次查找来获取该值。
@config: {
@colors: {
primary: blue;
}
}
.box {
color: @config[@colors][primary];
}
返回的查找值本身可以是变量。例如,你可以这样写:
@config: {
@dark: {
primary: darkblue;
}
@light: {
primary: lightblue;
}
}
.box {
@lookup: dark;
color: @config[@@lookup][primary];
}
这将输出:
.box {
color: darkblue;
}
发布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;
}
}
由于命名空间和重载 mixin 的能力,Mixins 作为地图来说更加灵活。
#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;
}
}
通过这种方式,规则集和变量调用可以模拟一种类似于混合的“命名空间”。
至于是否使用 mixin 或将规则集赋值给变量作为 map,则由您决定。您可能希望通过重新声明赋值给规则集的变量来替换整个 map。或者,您可能希望“合并”单个键/值对,在这种情况下,将 mixin 用作 map 可能更合适。
需要注意的一件重要事情是[@lookup]是键(变量)名称@lookup,并且不会被评估为变量。如果您希望键名本身成为变量,则可以使用@@variable句法。
例如
.foods() {
@dessert: ice cream;
}
@key-to-lookup: dessert;
.lunch {
treat: .foods[@@key-to-lookup];
}
这将输出:
.lunch {
treat: ice cream;
}
Less 的一些附加作用域特性
直观地讲,mixin 可以访问定义范围。
#ns {
@a: one;
.mixin-1() {
prop: @a;
}
}
.rule {
#ns.mixin-1();
}
/* OUTPUTS:
.rule {
prop: one;
}
*/
这是未来版本中可能被删除的混合范围功能列表。
#ns {
.mixin-1() {
prop: @a;
}
}
.rule {
@a: one;
#ns.mixin-1();
}
/* OUTPUTS:
.rule {
prop: one;
}
*/
这是违反直觉的,因为:
首选方法:传入您想要对 mixin 可见的变量。
#ns {
.mixin-1(@a) {
prop: @a;
}
}
.rule {
#ns.mixin-1(@a: one);
}
Mixins 会将其变量推送到调用者范围,但是仅有的如果变量不是局部定义的。
#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;
}
*/
这是违反直觉的,因为:
此外,通过引入 Maps,您可以直接检索变量值(和混合)。
首选方法:
#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;
}
*/
与弃用变量的行为类似,mixin 也会被推送到调用者作用域。然而,与变量不同的是,与合并作用域 mixin 同名的 mixin 会被合并。
#ns {
.mixin-1() {
prop-1: one;
prop-2: two;
}
}
.rule {
#ns();
.mixin-1();
.mixin-1() {
prop-3: three;
}
}
/* OUTPUT:
.rule {
prop-1: one;
prop-2: two;
prop-3: three;
}
*/
首选方法:直接调用mixin。
#ns {
.mixin-1() {
prop-1: one;
prop-2: two;
}
}
.rule {
.mixin-1() {
prop-3: three;
}
#ns.mixin-1();
.mixin-1();
}
/* OUTPUT:
.rule {
prop-1: one;
prop-2: two;
prop-3: three;
}
*/
这里有一个定义变量并将它们保存在某个私有范围内的技巧,以防止它们泄漏到全局空间。
& {
// Vars
@height: 100px;
@width: 20px;
// Don't define any prop:value on this scope (as doing so will generate (wrong) output).
.test {
height: @height;
width: @width;
}
}
.rest {
height: @height; // Name error: variable @height is undefined
}
这里,@height和@width仅针对由创建的范围定义& { ... }您还可以在规则内嵌套范围:
.some-module {
@height: 200px;
@width: 200px;
text-align: left;
line-height: @height; // 200px
& {
// Override original values
@height: 100px;
@width: auto;
.some-module__element {
height: @height; // 100px
width: @width; // 200px
}
.some-module__element .text {
line-height: (@height / 2); // 50px
}
}
& {
// Override original values
@height: 50px;
.some-module__another-element {
height: @height; // 50px
width: @width; // 200px
}
.some-module__another-element .text {
line-height: (@height / 2); // 25px
}
}
}
选择器周围的“if”
发布v1.5.0
与 Mixin Guards 类似,guards 也可以应用于 css 选择器,它是声明 mixin 然后立即调用它的语法糖。
例如,在 1.5.0 之前你必须这样做:
.my-optional-style() when (@my-option = true) {
button {
color: white;
}
}
.my-optional-style();
现在,您可以将防护装置直接应用于样式。
button when (@my-option = true) {
color: white;
}
您还可以实现if类型语句,将其与&功能,允许您对多名警卫进行分组。
& when (@my-option = true) {
button {
color: white;
}
a {
color: blue;
}
}
请注意,您还可以通过使用实际来实现类似的模式if()函数和变量调用。例如:
@dr: if(@my-option = true, {
button {
color: white;
}
a {
color: blue;
}
});
@dr();
发布v2.5.0
导入 JavaScript 插件以添加 Less.js 函数和特性
使用@pluginat-rule 类似于使用@import为了你的.less文件。
@plugin "my-plugin"; // automatically appends .js if no extension
由于 Less 插件是在 Less 范围内评估的,因此插件定义可以非常简单。
registerPlugin({
install: function(less, pluginManager, functions) {
functions.add('pi', function() {
return Math.PI;
});
}
})
或者你可以使用module.exports(已调整以在浏览器和 Node.js 中运行)。
module.exports = {
install: function(less, pluginManager, functions) {
functions.add('pi', function() {
return Math.PI;
});
}
};
请注意其他 Node.js CommonJS 约定,例如require()在浏览器中不可用。编写跨平台插件时请记住这一点。
插件能做什么?有很多,但我们先从基础开始。我们首先关注一下你可以在install函数。假设你写了这个:
// my-plugin.js
install: function(less, pluginManager, functions) {
functions.add('pi', function() {
return Math.PI;
});
}
// etc
恭喜!您已经编写了一个 Less 插件!
如果您要在样式表中使用它:
@plugin "my-plugin";
.show-me-pi {
value: pi();
}
您将获得:
.show-me-pi {
value: 3.141592653589793;
}
但是,如果您想将其与其他值相乘或执行其他 Less 操作,则需要返回一个合适的 Less 节点。否则,样式表中的输出将是纯文本(这可能适合您的目的)。
意思是,这是更正确的:
functions.add('pi', function() {
return new tree.Dimension(Math.PI);
});
注意:尺寸是一个有或没有单位的数字,例如“10px”,即less.Dimension(10, "px")。有关单位列表,请参阅更少的 API。
现在您可以在操作中使用您的功能。
@plugin "my-plugin";
.show-me-pi {
value: pi() * 2;
}
您可能已经注意到,您的插件文件有可用的全局变量,即函数注册表(functions对象)和less对象。这些都是为了方便起见。
添加的功能@pluginat-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 开始,函数可以返回任何类型的 Node 类型,并且可以在任何级别调用。
这意味着,这会在 2.x 中引发错误,因为函数必须是属性或变量赋值的一部分:
.block {
color: blue;
my-function-rules();
}
在 3.x 中,情况不再如此,函数可以返回 At-Rules、Rulesets、任何其他 Less 节点、字符串和数字(后两者转换为匿名节点)。
有时你可能想调用一个函数,但不想输出任何内容(例如存储一个值以供以后使用)。在这种情况下,你只需要返回false从函数中。
var collection = [];
functions.add('store', function(val) {
collection.push(val); // imma store this for later
return false;
});
@plugin "collections";
@var: 32;
store(@var);
稍后你可以做类似的事情:
functions.add('retrieve', function(val) {
return new tree.Value(collection);
});
.get-my-values {
@plugin "collections";
values: retrieve();
}
Less.js 插件应该导出具有一个或多个这些属性的对象。
{
/* Called immediately after the plugin is
* first imported, only once. */
install: function(less, pluginManager, functions) { },
/* Called for each instance of your @plugin. */
use: function(context) { },
/* Called for each instance of your @plugin,
* when rules are being evaluated.
* It's just later in the evaluation lifecycle */
eval: function(context) { },
/* Passes an arbitrary string to your plugin
* e.g. @plugin (args) "file";
* This string is not parsed for you,
* so it can contain (almost) anything */
setOptions: function(argumentString) { },
/* Set a minimum Less compatibility string
* You can also use an array, as in [3, 0] */
minVersion: ['3.0'],
/* Used for lessc only, to explain
* options in a Terminal */
printUsage: function() { },
}
PluginManager 实例install()函数提供了添加访问者、文件管理器和后处理器的方法。
这里有一些显示不同插件类型的示例 repos。
虽然@plugin调用在大多数情况下都能很好地工作,有时您可能希望在解析开始之前加载插件。
看:预加载插件在“使用 Less.js”部分中了解如何执行此操作。