文章目录
  1. 1. 变量(Variables)
    1. 1.1. 变量插值(Variable Interpolation)
  2. 2. Extend(扩展)
    1. 2.1. extend准确匹配
    2. 2.2. Extend all
    3. 2.3. Extend中的选择器插值
    4. 2.4. 作用域/@media内的extend
  3. 3. 混合(Mixins)
    1. 3.1. 不输出混合集
    2. 3.2. 带选择器的混合集
    3. 3.3. 命名空间
    4. 3.4. !important关键字
  4. 4. 带参混合(Parametric Mixins)
    1. 4.1. 多个参数
    2. 4.2. 命名参数
    3. 4.3. @arguments变量
    4. 4.4. 高级参数和@rest变量
    5. 4.5. 模式匹配
  5. 5. 作为函数使用的Mixins(Mixinss as Functions)
  6. 6. Passing Rulesets to Mixins
  7. 7. Import Directives
    1. 7.1. 文件扩展名
  8. 8. Import Options
    1. 8.1. reference
    2. 8.2. inline
    3. 8.3. less
    4. 8.4. css
    5. 8.5. once
    6. 8.6. multiple
  9. 9. Mixin Guards
    1. 9.1. Guard中的比较运算符
    2. 9.2. Guard logical operators
    3. 9.3. 类型检查
    4. 9.4. 带条件的mixins
  10. 10. CSS Guards
  11. 11. Loops
  12. 12. Merge
    1. 12.1. 逗号
    2. 12.2. 空格
  13. 13. Parent Selectors
    1. 13.1. 多个&
    2. 13.2. 改变选择器顺序
    3. 13.3. 组合使用的爆炸效果

上一篇Blog简单介绍了Less及其用法,本篇将着力介绍其语言特性。

作为一种 CSS 扩展, Less 不仅向后兼容 CSS, 它还使用现有的 CSS 语法新增了额外的特性. 这使得学习 Less 更轻松, 一旦有任何问题,可以随时退回使用标准的 CSS.

变量(Variables)

变量通过为你提供一种在一个地方管理一些值的方法让你的代码变得更容易维护:

// 变量
@link-color:        #428bca; // sea blue
@link-color-hover:  darken(@link-color, 10%);

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

变量是延迟加载的,在使用前不一定要预先声明。

在定义一个变量两次时,只会使用最后定义的变量,Less会从当前作用域中向上搜索。这个行为类似于CSS的定义中始终使用最后定义的属性值。例如:

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

编译为:

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

变量插值(Variable Interpolation)

变量除了可以管理值之外,还可以用在许多地方,比如选择器名称,属性名,URLs以及@import语句中。例如:

// 变量
@mySelector: banner;
@images: "../img";
@property: color;


// 用法
.@{mySelector} {
  background: url("@{images}/white-sand.png");
  @{property}: #0ee;
    background-@{property}: #999;
  font-weight: bold;
  line-height: 40px;
  margin: 0 auto;

}

编译为:

.banner {
  background: url("../img/white-sand.png");
  color:#0ee;
  background-color:#999;
  font-weight: bold;
  line-height: 40px;
  margin: 0 auto;
}

还可以使用变量来定义变量名:

@fnord:  "I am fnord.";
@var:    "fnord";
content: @@var;

这会编译为:

content: "I am fnord.";

Extend(扩展)

extend是一个Less伪类,它会合并它所在的选择器和它所匹配的引用。

extend可以附加给一个选择器,也可以放入一个规则集中。它看起来像是一个带选择器参数伪类,也可以使用关键字all选择相邻的选择器。例如:

.a:extend(.b) {}

// 上面的代码块与下面这个做一样的事情
.a {
  &:extend(.b);
}

.c:extend(.d all) {
  // 扩展".d"的所有实例,比如".x.d"或者".d.x"
}
.c:extend(.d) {
  // 扩展选择器输出为".d"的唯一实例
}

它可以包含多个要扩展的类,使用逗号分割即可。

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

// 上面的代码与下面的做一样的事情
.e:extend(.f, .g) {}

extend还可以匹配嵌套选择器,比如有下面的Less:

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

输出是:

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

extend准确匹配

Extend默认会在选择器之间寻找精确匹配。它不管选择器是以星号开始还是不是。它也不管两个nth表达式(1n+3 和 n+3不能匹配)是否具有相同的意义,它们必须以相同的形式匹配。唯一例外的是属性选择器中的引号,less会知道它们是相同的,然后匹配它。例如:

.a.class,
.class.a,
.class > .a {
  color: blue;
}
*.class {
  color: blue;
}

.test:extend(.class) {} // 不会匹配上面的任何选择器的值

Extend all

当你在extend参数的最后面指定all关键字时,它会告诉告诉匹配作为其他选择器一部分的选择器。这个选择器会被复制,然后匹配的选择器部分会使用扩展替换,创建一个新的选择器。例如:

.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不能匹配变量选择器。如果选择器包含变量,extend会忽略它。但是extend可以附加给插值选择器。例如:

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

:extend 附加给插值选择器是能够工作的:

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

上面的例子会编译为:

.bucket, .selector {
  color: blue;
}

作用域/@media内的extend

编写在media声明内的extend也应该只匹配同一media声明内的选择器;

编写在media声明内的extend不会匹配嵌套声明内的选择器:

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

顶级extend匹配一切,包括media嵌套内的选择器:

@media screen {
  .selector {  /* media嵌套内的规则 - 顶级extend正常工作 */
    color: blue;
  }
  @media (min-width: 1023px) {
    .selector {  /* media嵌套内的规则 - 顶级extend正常工作 */
      color: blue;
    }
  }
}

.topLevel:extend(.selector) {} /* 顶级extend匹配一切 */

编译为:

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

不存在重复检测。

混合(Mixins)

可以混合“类”选择器或者“id”选择器,例如:

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

输出:

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

不输出混合集

在混合集的名字后面加上一个括号。例如:

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

输出:

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

带选择器的混合集

混合集不仅可以包含各种属性,而且可以包括各种选择器。

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

结果为:

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

命名空间

如果你想要将属性混合到比较复杂的选择器中,你可以通过嵌套多层id或者class。

!important关键字

在调用的混合集后面追加 !important 关键字,可以使混合集里面的所有属性都继承 !important。例如:

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

结果为:

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

带参混合(Parametric Mixins)

mixins也可以接受参数,在它进行mix in操作时会将变量传递给选择器代码块。对于这些进行mixin操作的参数也可以有默认值.

多个参数

参数可以用分号或者逗号分割。但是推荐使用分号分割。因为逗号符号有两个意思:它可以解释为mixins参数分隔符或者css列表分隔符。

使用逗号作为mixin的分隔符则无法用它创建逗号分割的参数列表。换句话说,如果编译器在mixin调用或者声明中看到至少一个分号,它会假设参数是由分号分割的,而所有的逗号都属于CSS列表:

两个参数,并且每个参数都是逗号分割的CSS列表:.name(1,2,3;something, ele)

定义多个具有相同名称和参数数量的mixins是合法的。Less会使用它可以匹配的所有mixins。例如:

.mixin(@color) {
  color-1: @color;
}
.mixin(@color; @padding:2) {
  color-2: @color;
  padding-2: @padding;
}
.mixin(@color; @padding; @margin: 2) {
  color-3: @color;
  padding-3: @padding;
  margin: @margin @margin @margin @margin;
}
.some .selector div {
  .mixin(#008000);
}

会编译为:

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

命名参数

引用mixin时可以通过参数名称而不是参数的位置来为mixin提供参数值。任何参数都已通过它的名称来引用,这样就不必按照任意特定的顺序来使用参数:

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

会编译为:

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

@arguments变量

@arguments在mixins内部有特殊意义,调用mixin时,它包含所有传入的参数。如果你不想单个单个的处理参数,这一特性是很有用的:

.box-shadow(@x: 0; @y: 0; @blur: 1px; @color: #000) {
  -webkit-box-shadow: @arguments;
     -moz-box-shadow: @arguments;
          box-shadow: @arguments;
}
.big-block {
  .box-shadow(2px; 5px);
}

结果是:

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

高级参数和@rest变量

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

.mixin(...) {        // matches 0-N arguments
.mixin() {           // matches exactly 0 arguments
.mixin(@a: 1) {      // matches 0-1 arguments
.mixin(@a: 1; ...) { // matches 0-N arguments
.mixin(@a; ...) {    // matches 1-N arguments

此外:

.mixin(@a; @rest...) {
   // @rest 会绑定到参数 @a 之后
   // 而@arguments是绑定所有参数
}

模式匹配

有时候,你可能想要基于你传递给它的参数改变mixin的行为。比方说你想要.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;
}

作为函数使用的Mixins(Mixinss as Functions)

所有定义在一个mixin中的变量都是可见的,在调用域中都可以使用。定义在mixin中的变量还可以充当它的返回值。这样就允许我们创建一个用起来类似函数的mixin。

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

div {
  .average(16px, 50px); // "call" the mixin
  padding: @average;    // use its "return" value
}

结果:

div {
  padding: 33px;
}

Passing Rulesets to Mixins

你可能希望定义一个mixin将一个媒体查询中的一个代码块或者一个浏览器不支持的类名抽象出来。现在,你可以传递规则集给mixin,然后该mixin会包装这些规则集。比如:

.desktop-and-old-ie(@rules) {
  @media screen and (min-width: 1200) { @rules(); }
  html.lt-ie9 &                       { @rules(); }
}

header {
  background-color: blue;

  .desktop-and-old-ie({
    background-color: red;
  });
}

这里的desktop-and-old-ie mixin定义了媒体查询和祖先类,因此你可以使用mixin来包装一段代码。上面这段代码会输出:

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

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

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

which will output

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

这边不懂哎。。。。

Import Directives

从其他样式表中导入样式。Less.js不在乎你把@import语句放在什么位置。

文件扩展名

@import语句会通过Less依赖文件扩展名的方式区别对待不同的文件:

  1. 如果文件有一个.css扩展名,则将它作为CSS对象,同时@import语句保持不变(查看下面的inline选项)
  2. 如果有其他扩展名,则作为Less对象,然后导入它。
  3. 如果没有扩展名,则插入.less,然后将它作为Less文件导入包含进来。

Import Options

Less提供了一系列的CSS扩展来让你使用@import更灵活的导入第三方CSS文件。语法:

@import (keyword) "filename";

下面导入指令已经被实现了:

reference:使用Less文件但不输出
inline:在输出中包含源文件但不加工它
less:将文件作为Less文件对象,无论是什么文件扩展名
css:将文件作为CSS文件对象,无论是什么文件扩展名
once:只包含文件一次(默认行为)
multiple:包含文件多次

reference

使用@import (reference)导入外部文件,但是不添加导入的样式到编译输出中,只引用。

inline

使用@import (inline)引入外部文件,但不加工他们。

当一个CSS文件可能不兼容Less的时候可以使用这一技术,这是因为尽管Less支持大多数熟知的标准的CSS,但是在有些地方它还是不支持注释,在不修改CSS的情况下它也不支持所有已知的CSS hacks。

因此你可以使用它来在输出中引入文件,最终CSS文件都会在一个地方。

less

使用@import (less)会将导入的文件作为Less文件对象,不管文件扩展名是什么。

css

使用@import (css)会将带入的文件作为普通的CSS文件对象,也不会管扩展名是什么。

once

@import语句的默认行为。这意味着文件只会被导入一次,而随后的导入文件的语句都会被忽略。@import的默认行为。

multiple

使用@import (multiple)允许导入多个同名文件。这与只能导入一次的行为是对立的。例如:

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

输出:

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

Mixin Guards

当你想要匹配表达式,而不是简单的值或者参数数量时,guard是很有用的。

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

这里有一个when关键字,它引进了一个guard序列(在这里只有一个guard)。现在,假设我们运行以下代码:

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

会得到:

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

Guard中的比较运算符

guards中可用的比较运算符的完整列表为: >, >=, =, =<, <。此外,关键字true是让两个mixins等价的唯一真值,除了关键字true,其他任何值都是假值。

Guards可以使用逗号,分割,如果任何一个guards(逗号分隔的多个guards)求值为true,它就被认为是一个相等的匹配。

Guard logical operators

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

Use the and keyword to combine guards

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

Use the not keyword to negate conditions

类型检查

如果你想基于值类型匹配mixins,那么你可以使用is函数.例如:

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

带条件的mixins

此外,default函数可以用于让一个mixin匹配依赖于其他mixin匹配,然后你可以使用它来创建类似于else或者default语句(分别属于if和case结构)的“条件式mixins”:

.mixin (@a) when (@a > 0) { ...  }
.mixin (@a) when (default()) { ... } // matches only if first mixin does not, i.e. when @a <= 0

CSS Guards

约束也适用于CSS选择器

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

你还可以通过与&特性结合实现’if’类型的语句,从而允许组合多个约束。

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

Loops

在Less中,混合可以调用它自身。这样,当一个混合递归调用自己,再结合Guard表达式和模式匹配这两个特性,就可以写出循环结构。

使用递归循环最常见的情况就是生成栅格系统的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%;
}

Merge

merge特性可以从多个属性中将值集合集合到一个单一属性之下的逗号或空格分割属性列表中。对于诸如background和transform之类的属性来说,merge非常有用。

逗号

示例:

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

空格

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

Outputs

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

为避免任何非有意的添加,merge需要在每个待加入的声明中显示的设置一个+或者+_标记。

Parent Selectors

&运算符表示一个嵌套规则的父选择器,它在应用修改类或者应用伪类给现有选择器时最常用。

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

结果为:

a {
  color: blue;
}

a:hover {
  color: green;
}

注意,如果上面的示例没有使用&,那么它的结果就是a :hover(一个匹配<a>标签内的hovered元素的后代选择器),这通常并不是我么想要的嵌套的:hover的结果。

“父选择器”有各种各样的用法。基本上,任何时候你都需要以不同的方式来组合选择器嵌套的规则,而不是默认规则。比如,一个使用&的典型的场景就是生成重复的类名:

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

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

改变选择器顺序

要前置插入一个选择器给继承的(父)选择器时它是很有用的。用过将&放到当前选择器之后就可以做到这一点。比如:

.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;
}
文章目录
  1. 1. 变量(Variables)
    1. 1.1. 变量插值(Variable Interpolation)
  2. 2. Extend(扩展)
    1. 2.1. extend准确匹配
    2. 2.2. Extend all
    3. 2.3. Extend中的选择器插值
    4. 2.4. 作用域/@media内的extend
  3. 3. 混合(Mixins)
    1. 3.1. 不输出混合集
    2. 3.2. 带选择器的混合集
    3. 3.3. 命名空间
    4. 3.4. !important关键字
  4. 4. 带参混合(Parametric Mixins)
    1. 4.1. 多个参数
    2. 4.2. 命名参数
    3. 4.3. @arguments变量
    4. 4.4. 高级参数和@rest变量
    5. 4.5. 模式匹配
  5. 5. 作为函数使用的Mixins(Mixinss as Functions)
  6. 6. Passing Rulesets to Mixins
  7. 7. Import Directives
    1. 7.1. 文件扩展名
  8. 8. Import Options
    1. 8.1. reference
    2. 8.2. inline
    3. 8.3. less
    4. 8.4. css
    5. 8.5. once
    6. 8.6. multiple
  9. 9. Mixin Guards
    1. 9.1. Guard中的比较运算符
    2. 9.2. Guard logical operators
    3. 9.3. 类型检查
    4. 9.4. 带条件的mixins
  10. 10. CSS Guards
  11. 11. Loops
  12. 12. Merge
    1. 12.1. 逗号
    2. 12.2. 空格
  13. 13. Parent Selectors
    1. 13.1. 多个&
    2. 13.2. 改变选择器顺序
    3. 13.3. 组合使用的爆炸效果