Less 使用简记

一直以来,对 css 都是那么无力,最近项目需要,折腾了一下 less。这里只是记录一下一下我使用过程中的问题,熟悉 less 的盆友可以 cmd+w 了。

安装

很简单,npm

1
npm i less

如果要使用命令行就要全局安装 -g

使用

Compile

1
2
3
4
5
6
7
8
9
10
11
12
var less = require('less');
var sourceCode = '...'; // 源码字符串
var options = {
compress: true, // 是否压缩
globalVars: {
var1: 'val1'
},
modifyVars: {
var2: 'val2'
}
}
var lessPromise = less.render(sourceCode, options);

less.render 返回的是一个 Promise,如果只是一个操作,大可以直接 .then() 继续。还可以充分利用 Promise 的优势,如批量操作时 Promise.all([...])

globalVars & modifyVars

官方的定义:

globalVars

List of global variables to be injected into the code. Keys of the object are variables names, values are variables values. Variables of “string” type must explicitly include quotes if needed.

modifyVars

As opposed to the globalVars option, this puts the declaration at the end of your base file, meaning it will override anything defined in your Less file.

globalVarsmodifyVars 非常好用,因为有了这两个配置,就可以把 js 里面的一些变量传递到 less 中。globalVars 可以做默认值,modifyVars做重置值。

命令行

lessc 是标准输出

1
lessc file.less > out.css

具体用法还是看官网吧。

语法

嵌套

1
2
3
4
5
6
7
8
9
body {
color: #333;
.main {
background: #eee;
p {
color: #666;
}
}
}

编译后:

1
2
3
4
5
6
7
8
9
body {
color: #333;
}
body .main {
background: #eee;
}
body .main p {
color: #666;
}

变量

1
2
3
4
@var1: #fff;
body {
color: @var1;
}

选择器

1
2
3
4
@my-selector: banner;
.@{my-selector} {
color: #fff;
}

特殊字符

  • 传入的参数需要用引号 " 包住字符串
  • 使用时用大括号 {} 包住变量
  • 变量必须在字符串内 '@{var}'
1
2
3
4
5
6
7
@imgPath: "/path/to/bg.png";
.bg {
background: url('@{imagePath}');
}
.bg2 {
background: url('append/url/@{imagePath}');
}

如果使用 globalVarsmodifyVars 时,也要注意:

1
2
3
4
5
less.render(sourceCode, {
modifyVars: {
imgPath: '"/path/to/bg.png"' // 注意,里面还有一对双引号
}
});

When

只能用于判断 boolean 值的条件语句:

1
2
3
4
5
6
7
8
@condition1: true;
@condition2: #fff;
.btn when (@condition1) { /* 这里判断成功 */
width: 100px;
}
.btn when (@condition2) { /* 这里判断失败 */
height: 25px;
}

编译后:

1
2
3
.btn {
width: 100px;
}

同样也有 when not 可以使用:

1
2
3
4
5
6
7
@img: "path/to/img.png";
.btn when (@img = "") {
background-color: #fff;
}
.btn when not (@img = "") {
background-image: url(@img);
}

编译后:

1
2
3
.btn {
background-image: url(path/to/img.png);
}

Extend

适用一些共同样式的情况,如:

1
2
3
4
5
6
7
8
9
10
11
12
.btn {
width: 100px;
height: 25px;
color: #fff;
}

.btn-red:extend(.btn) {
background: red;
}
.btn-blue:extend(.btn) {
background: blue;
}

编译后:

1
2
3
4
5
6
7
8
9
10
11
12
13
.btn,
.btn-red,
.btn-blue {
width: 100px;
height: 25px;
color: #fff;
}
.btn-red {
background: red;
}
.btn-blue {
background: blue;
}

在嵌套里面使用

如下 less 代码:

1
2
3
4
5
6
7
8
.main {
.title {
color: #ccc;
}
.subtitle:extend(.title) {
font-size: 14px;
}
}

会报错误 extend ' .title' has no matches,需要这样实现

1
2
3
4
5
6
7
8
.main {
.title {
color: #ccc;
}
.subtitle:extend(.main .title) { // 注意这里
font-size: 14px;
}
}

这我就不太能接受了,嵌套里面居然还要我知道这个 .title 的上一级是 .main 才能嵌套,如果是更多级的就很别扭了。看到 Github 上的这个 issue #1730 也没有完美的答案。

Mixin

mixin 同样能实现上面的功能,但大多数情况编译结果代码量会更多,因为 mixin 是行内的。

1
2
3
4
5
6
7
8
9
10
11
12
13
.btn {
width: 100px;
height: 25px;
color: #fff;
}
.btn-red {
.btn();
background: red;
}
.btn-blue {
.btn();
background: blue;
}

编译后:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
.btn {
width: 100px;
height: 25px;
color: #fff;
}
.btn-red {
width: 100px;
height: 25px;
color: #fff;
background: red;
}
.btn-blue {
width: 100px;
height: 25px;
color: #fff;
background: blue;
}

而 mixin 真正的优势在于其 函数化 方法,同样是上面的功能,我们可以这样写:

1
2
3
4
5
6
7
8
9
10
11
12
.btn(@bgColor) { // 注意这里有个括号,里面带有参数
width: 100px;
height: 25px;
color: #fff;
background: @bgColor;
}
.btn-red {
.btn(red);
}
.btn-blue {
.btn(blue);
}

编译后:

1
2
3
4
5
6
7
8
9
10
11
12
.btn-red {
width: 100px;
height: 25px;
color: #fff;
background: red;
}
.btn-blue {
width: 100px;
height: 25px;
color: #fff;
background: blue;
}

可以看到,这次的编译结果已经没有 .btn 了,我理解 () 使其作为函数声明存在,本身不产生 css,只有在被调用时才将其函数体 {} 里的内容赋予调用者。

在嵌套中使用

mixin 在嵌套中就没有那么多问题了:

1
2
3
4
5
6
7
8
9
.main {
.title {
color: #ccc;
}
.subtitle {
.title;
font-size: 14px;
}
}

1
2
3
4
5
6
7
8
9
.main {
.title(@color) {
color: @color;
}
.subtitle {
.title(#ccc);
font-size: 14px;
}
}

都能分别得到相应的结果,但这两者是有区别的,前者会产生 .main .title 而后者不会。

如果要在嵌套外调用,这样也很合理:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
.main {
.title(@color) {
color: @color;
}
.subtitle {
.title(#ccc);
font-size: 14px;
}
}

.other {
.main .title(#ccc); // 注意这里
font-size: 12px;
}