初识 Less

Less 是什么

Less 是一门 CSS 预处理语言,它扩展了 CSS 语言,增加了变量、Mixin、函数等特性,使 CSS 更易维护和扩展。 Less 可以运行在 Node 或浏览器端。最基础的例子如下所示:

1
2
3
4
5
6
7
8
9
@base: #fff;
.wh(@width, @height) {
width: @width;
height: @height;
}
.box {
color: @base;
.wh('30px', '30px')
}

编译输出后的结果:

1
2
3
4
5
.box {
color: #fff;
width: '30px';
height: '30px';
}

浏览器中使用 Less

我们如何在网页中使用 Less 呢?有两种形式,第一种是通过 npm 下载 Less 包,通过 webpack 打包编译后可以编译成最终的 CSS。第二种是直接通过 Less 脚本在 HTML 页面中使用。 本章为了方便学习 Less 的语法知识,选择第二种形式。首先我们创建一个 Less 文件夹,在文件夹内新建一个 index.html 文件,和style.less文件:

image-20210316091543094

随后我们需要去找 Less 的静态资源,在此推荐大家一个好用的静态资源网站,里面有很多前端相关的静态资源— BootCDN。 最后我们练手的 index.html 代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet/less" type="text/css" href="./styles.less" />
<title>Document</title>
</head>
<body>
<div class="box">
<span>我是less</span>
</div>
<script src="https://cdn.bootcss.com/less.js/3.11.1/less.min.js"></script>
</body>
</html>

styles.less 代码如下:

1
2
3
4
5
.box {
span {
color: red;
}
}

浏览器中的效果如下:

image-20210316094929730

Less 的使用

Less 中的注释

  • // 开头的注释,注释单行,且不会被编译到 CSS 文件中。
  • /**/ 包裹的注释,注释多行,同样也不会被编译到 CSS 文件中。

Less 中的变量

Less 中使用 @ 符号申明变量,比如 @color: red。比方说我现在写一个电商项目,我需要设置项目中主色、辅助色等,代码如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet/less" type="text/css" href="./styles.less" />
<title>Document</title>
</head>

<body>
<div class="box">
<p class="one">我是less</p>
<p class="two">我是less</p>
<p class="three">我是less</p>
</div>
<script src="https://cdn.bootcss.com/less.js/3.11.1/less.min.js"></script>
</body>

</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// styles.less
@primary: red;
@deepColor: green;
@lightColor: blue;

.box {
.one {
color: @primary;
}
.two {
color: @deepColor;
}
.three {
color: @lightColor;
}
}

image-20210316095017227

有一点要注意的是,如果在后面声明了同名变量,变量值会被后面的覆盖,比如上述代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// styles.less
@primary: red;
@deepColor: green;
@lightColor: blue;
@primary: pink

.box {
.one {
color: @primary;
}
.two {
color: @deepColor;
}
.three {
color: @lightColor;
}
}

那么第一个p标签.one下的“我是Jungle”就会为pink,即:同权重选择器前后覆盖。

程序员要培养自己的举一反三能力,颜色可以写成变量,文字的大小同样也可以,并且 less 文件能通过 @import 关键词引入其他的 less 文件

Less 中的嵌套

市面上所有 CSS 的预编译器的嵌套规则大同小异,基本嵌套如下:

1
2
3
4
5
6
.a {
color: #fff;
.b {
width: 20px;
}
}

编译后的代码如下所示:

1
2
3
4
5
6
.a {
color: #fff;
}
.a .b {
width: 20px;
}

同级场景 & 的使用如下所示:

1
2
3
4
5
6
.a {
color: blue;
&:hover {
color: red;
}
}

上述代码 & 表示当前节点的 CSS 样式,一般用于处理 CSS 样式的状态 hover、focus、active、link、visited等。

Less 中的混合(Mixin)

Less 的混合有三种情况:

  • 不带参数;
  • 带参数,没有默认值;
  • 带参数,且有设置默认值;

调用的时候也存在区别:

  • 不带参数:调用时可以不加括号,直接使用;
  • 带参数:调用时要加括号,括号里必须要传值,不然编译会报错;
  • 带参数且有默认值:调用时要加括号,参数可传可不穿;

下面就用上面的 Demo 页面进行实验,首先是第一种情况,不带参数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet/less" type="text/css" href="./styles.less" />
<title>Less</title>
</head>
<body>
<div class="box">
<p class="one">我是less</p>
</div>
<script src="https://cdn.bootcss.com/less.js/3.11.1/less.min.js"></script>
</body>
</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
.center {
text-align: center;
}
.red {
color: red;
}

.box {
.one {
.center;
.red;
}
}

image-20210316095056604

下面是带参数,且没有默认值的情况:

1
2
3
4
5
6
7
8
9
10
11
12
13
.center {
text-align: center;
}
.color(@c) {
color: @c;
}

.box {
.one {
.center;
.color(green);
}
}

image-20210316095112935

最后是带默认值的情况:

1
2
3
4
5
6
7
8
9
10
11
12
13
.center {
text-align: center;
}
.color(@c: red) {
color: @c;
}

.box {
.one {
.center;
.color;
}
}

image-20210316095130380

在开发页面时,时常会有需要画三角形的情况,上下左右四个方位的三角形,若是一直复制重复的代码去修改,显得不是那么优雅,这时候我们可以用到匹配模式。 匹配模式下无论同名的哪一个混合被匹配到,都会先执行通用匹配模式的代码, @_ 表示通用的匹配模式,具体代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet/less" type="text/css" href="./styles.less" />
<title>Less</title>
</head>
<body>
<div class="box">
<p></p>
</div>
<script src="https://cdn.bootcss.com/less.js/3.11.1/less.min.js"></script>
</body>
</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
.triangle(@_, @width, @color) {
width: 0;
height: 0;
border-style: solid;
}
.triangle(Bottom, @width, @color) {
border-width: @width;
border-color: @color transparent transparent transparent;
}
.triangle(Left, @width, @color) {
border-width: @width;
border-color: transparent @color transparent transparent;
}
.triangle(Top, @width, @color) {
border-width: @width;
border-color: transparent transparent @color transparent;
}
.triangle(Right, @width, @color) {
border-width: @width;
border-color: transparent transparent transparent @color;
}

.box {
p {
.triangle(Left, 100px, red);
}
}

上述 Less 代码设置了基础的 .triangle 样式,再分别设置上下左右四个方位的匹配模式,并且可以通过 @width 参数来控制三角形大小,浏览器的展示如下所示:

image-20210316093712171

你可以把配置写进共用的样式库中,在需要用到的地方通过 @import 关键字引入。

arguments 变量:使用 @arguments 表示 mixin 的所有参数,代码示例如下:

1
2
3
4
5
6
7
.border(@width, @mode, @color) {
border: @arguments;
}

.one {
.border(1px, solid, red)
}

Less 中的运算

算数运算符 +、-、*、/ 可以对任何数字、颜色或者变量进行运算,在 Less 中在加减之前会进行单位的换算。计算的结果以最左侧才作数的单位类型为准。如果单位无效或者失去意义,则单位会被忽略。

1
2
width: 20px + 20; // 输出结果为 40px
color: #444 * 2; // 输出结果为 #888888

calc() 特例

为了与 CSS 保持兼容, calc() 方法并不会对数学表达式进行计算,但是在嵌套函数中会计算变量的数学公式的值。代码如下所示:

1
2
@a: 100vh/2
height: calc(50% + (@a - 40px)); // 输出结果为: calc(50% - (50vh - 40px))

Less 中的转译

转译,简单的理解就是我们原先是什么样的,最终输出的还是什么样。关键字是 ~"",示例代码如下:

1
2
3
p {
color: ~"green"; // 编译后的输出结果还是 color: green;
}

在 Less 3.5+ 版本中,许多以前需要“引号转义”的情况就不再需要了。

Less 中的作用域

Less 中的作用域和 CSS 的作用域非常相似,首先 Less 会查询当前作用域内的变量和混合(mixins),如果找不到的话会继续向上一级查询,直到找到为止。示例代码如下:

1
2
3
4
5
6
7
@var: blur;
body {
@var: red;
.one {
color: @var; // 编译后输出的结果为:color: red;
}
}

Less 中的导入

现代前端开发,万物皆是模块。Less 也不例外,我们一个 Less 文件就可以当作一个模块来处理,一个 Less 文件中可以引入另外一个 Less 文件,并且可以使用里面的变量信息,我们来看实例代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet/less" type="text/css" href="./styles.less" />
<title>Less</title>
</head>
<body>
<div class="box">
<p>我是P</p>
</div>
<script src="https://cdn.bootcss.com/less.js/3.11.1/less.min.js"></script>
</body>
</html>
1
2
3
4
5
6
7
8
9
10
// styles.less
@import './styles1.less';

@color1: red;

.box {
p {
color: @color2;
}
}
1
2
// styles1.less
@color2: blue;

image-20210316095213862

声明变量的时候,颜色主题可以单独创建一个 Less 文件。字体大小,文字粗细,阴影的大小,透明度等等也可以单独抽离一个 Less 文件,通过引入的方式全部引入到 index.less 中,在组件中使用的时候,可以只引入 index.less 文件,便可使用在 index.less 中引入的 Less 文件的变量。

Less 使用实例

文字超出省略

这是前端开发中出现频率比较高的情况,我们来提取混合(Mixin),实例代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet/less" type="text/css" href="./styles.less" />
<title>Less</title>
</head>
<body>
<div class="box">
<div class="text">我是less我是less我是less我是less我是less我是less我是less</div>
</div>
<script src="https://cdn.bootcss.com/less.js/3.11.1/less.min.js"></script>
</body>
</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
.ellipsisSingle {
-webkit-box-orient: vertical;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}


.box {
.text {
.ellipsisSingle;
background: darkgoldenrod;
width: 200px;
height: 20px;
}
}

image-20210316095255000

若是需要多行省略的情况呢?下面就用到了带参数的混合(Mixin):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet/less" type="text/css" href="./styles.less" />
<title>Less</title>
</head>
<body>
<div class="box">
<div class="text">我是less我是less我是less我是less我是less我是less我是less</div>
</div>
<script src="https://cdn.bootcss.com/less.js/3.11.1/less.min.js"></script>
</body>
</html>

styles.less:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
.ellipsisMultiple(@num: 1) {
display: -webkit-box;
-webkit-box-orient: vertical;
overflow: hidden;
text-overflow: ellipsis;
-webkit-line-clamp: @num;
}


.box {
.text {
.ellipsisMultiple(2);
background: darkgoldenrod;
width: 200px;
}
}

image-20210316095344056

文字垂直居中

很多时候你在写 CSS 样式的时候,会连续写两个连在一起的属性,比如 height: 20px; line-height: 20px,目的是为了让标签内的文字垂直居中,写多了就会觉得代码不是那么干净。又到了 Less 出手的时候了,把它封装起来,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
.line-text-h (@h: 0) {
height: @h;
line-height: @h;
}

.box {
.text {
.line-text-h(100px);
background: darkgoldenrod;
width: 200px;
}
}

image-20210316094503475

定位上下左右居中

项目开发中有些场景比如设置空页面的图标上下左右居中,这时我们可以封装一个 Less 混合(Mixin):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
.center {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}

.box {
.text {
.center;
background: darkgoldenrod;
width: 200px;
height: 200px;
}
}

image-20210316094555869

三角形绘制

三角形的绘制在开发中也是很常见,特别是上下左右四个方向的三角形,每次编写的时候代码都非常冗余,会有不少重复代码,在此我们可以使用 Less 传入参数的形式,控制三角形的样式和方向:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet/less" type="text/css" href="./styles.less" />
<title>Less</title>
</head>
<body>
<div class="box">
<p></p>
</div>
<script src="https://cdn.bootcss.com/less.js/3.11.1/less.min.js"></script>
</body>
</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
.triangle(@_, @width, @color) {
width: 0;
height: 0;
border-style: solid;
}
.triangle(Bottom, @width, @color) {
border-width: @width;
border-color: @color transparent transparent transparent;
}
.triangle(Left, @width, @color) {
border-width: @width;
border-color: transparent @color transparent transparent;
}
.triangle(Top, @width, @color) {
border-width: @width;
border-color: transparent transparent @color transparent;
}
.triangle(Right, @width, @color) {
border-width: @width;
border-color: transparent transparent transparent @color;
}

.box {
p {
.triangle(Top, 100px, blue);
}
}

image-20210316094722022

总结

市面上 CSS 预编译器大同小异,语法大抵相同,不同的可能是一些变量符号,学好 Less,切换 Sass 或是 Stylus 都是比较轻松的。

规划好 Less 文件,在实际开发项目中能事半功倍,可以把更多的精力放在业务逻辑上,而不会因为改一个样式问题导致“牵一发动全身”。