Less语言特性

593 阅读7分钟

Less GitHub

Variables(变量)

在你的样式表中相同的值重复几十次 甚至上百次 并不少见,变量通过为你提供一种在一个地方管理这些值的方法让你的代码变得更容易维护。

@nice-blue: #5B83AD;
@light-blue: @nice-blue + #111;
#header {
  color: @light-blue;
}

//作为属性名
@mySelector: banner;
.@{mySelector} {
  font-weight: bold;
  line-height: 40px;
  margin: 0 auto;
}

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

// 作为import引入
@themes: "../../src/themes";
@import "@{themes}/tidal-wave.less";

// 作为属性
@property: color;
.widget {
  @{property}: #0ee;
  background-@{property}: #999;
}

// 作为变量
@fnord:  "I am fnord.";
@var:    "fnord";
content: @@var;

由于变量只能定义一次,实际上也相当于常量。

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

同名变量后面的会覆盖前面的。

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

输出:

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

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) {}

如果你想有一个animal子类型,并且要重写背景颜色。那么你有两个选择:

1.首先改变你的HTML
<a class="animal bear">Bear</a>

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

2.简化你的HTML
<a class="bear">Bear</a>

.animal {
  background-color: black;
  color: white;
}
.bear {
  &:extend(.animal);
  background-color: brown;
}

Mixins会复制所有的属性到选择器中,这可能导致不必要的重复。因此你可以使用extend来代替mixin将你要用的属性移过去,这样就会生成更少的CSS。

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

// 或者
.my-inline-block {
  display: inline-block;
  font-size: 0;
}
.thing1 {
  &:extend(.my-inline-block);
}
.thing2 {
  &:extend(.my-inline-block);
}
// 编译为:
.my-inline-block,
.thing1,
.thing2 {
  display: inline-block;
  font-size: 0;
}
Mixins(混入)

从现有的样式混合(mixin)属性。

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

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

.c {
  #outer > .inner;
}
// 下面四种写法效果是一样的
#outer > .inner;
#outer > .inner();
#outer.inner;
#outer.inner();

在调用的混合集后面追加 !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;
}

mixinx参数

mixins也可以接受参数,在它进行mix in操作时会将变量传递给选择器代码块。

// 比如:
.border-radius(@radius) {
  -webkit-border-radius: @radius;
     -moz-border-radius: @radius;
          border-radius: @radius;
}
// 用法
#header {
  .border-radius(4px);
}
.button {
  .border-radius(6px);
}
// 对于这些进行mixin操作的参数也可以有默认值
.border-radius(@radius: 5px) {
  -webkit-border-radius: @radius;
     -moz-border-radius: @radius;
          border-radius: @radius;
}

多个参数的mixins

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

定义多个具有相同名称和参数数量的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 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);
}

// 编译为:
.class {
  color: #a2a2a2;
  display: block;
}

你也可以基于参数数量来匹配,这里有个例子:

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

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

所有定义在一个mixin中的变量都是可见的,还可以用于调用它的作用域中(除非调用它的作用域定义了同名变量)。

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

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

// 编译为:
.caller {
  width:  100%;
  height: 200px;
}

因此定义在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;
}

直接定义在调用者作用域内的变量不能被重写。然而,定义在变量调用者父级作用域内的变量是不是受保护的,将被重写:

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

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

@size: globaly-defined-value; // 调用者父级作用域 - 不受保护

// 编译为:
.class {
  margin: in-mixin in-mixin;
}

定义在mixin中的mixin同样可以作为返回值:

.unlock(@value) { // 外层的 mixin
  .doSomething() { // 被嵌套的 mixin
    declaration: @value;
  }
}

#namespace {
  .unlock(5); // unlock doSomething mixin
  .doSomething(); //嵌套混入被复制到这里,并可用
}

// 编译为:
#namespace {
  declaration: 5;
}

Import Directives(导入准则)

从其他样式表中导入样式。

在标准的CSS中,@import必须在所有其他类型的规则之前。但是Less.js不在乎你把@import语句放在什么位置。

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

Import Options (导入选项)

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

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

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