Less

什么是CSS预处理器

Less中文网: https://less.bootcss.com/

  • CSS 预处理器就是用某一种语言用来为 CSS 增加一些动态语言的的特性(变量、函数、继承等),

  • CSS 预处理器可以让你的 CSS 更见简洁,适应性更强,代码更直观等诸多好处

  • 简而言之:CSS 预处理器就是升级版 CSS

常见的CSS预处理器

  • Less(Leaner Style Sheets) 、Sass 、Stylus

为什么需要less

  • CSS 的语法虽然简单,但它同时也带来一些问题

  • CSS 需要书写大量看似没有逻辑的代码,不方便维护及扩展,也不利于复用

  • 造成这些原因的本质源于 CSS 是一门非程序式的语言,没有变量 / 函数 / 作用域等概念

什么是less

  • Less 是一门 CSS 预处理语言,为 CSS 赋予了动态语言的特征。
  • 它扩展了 CSS 语言,增加了变量、Mixin(混合)、嵌套、函数和运算等特性,使 CSS 更易维护和扩展
  • 一句话:用类似 JS 的语法去写 CSS

less基本使用

  • 在浏览器中直接运行
    • 编写 .less 文件–>引入 .less 文件–> 引入less.js
  • 运行注意点:
    • 一定要先引入 less.css , 再引入 less.js
    • 如果 less 代码是写到单独的文件中,一定要在服务端环境运行才能生效
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
.box {
font-size: 20px;
}
.center {
text-align: center;
}
.father {
width: 100px;
height: 100px;
.box;
.son {
color: red;
.center;
}
}
  • 编译结果如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
.box {
font-size: 20px;
}
.center {
text-align: center;
}
.father {
width: 100px;
height: 100px;
font-size: 20px;
}
.father .son {
color: red;
text-align: center;
}

提前预编译

  • 编写 less 文件–>利用工具转换为 css 文件–>引入 css 文件
  • VScode插件: Easy Less (推荐)
  • 考拉客户端: http://koala-app.com/index-zh.html
  • 开源中国 : https://tool.oschina.net/less
  • 构建工具配置 loader 自动编译:
  • 后续课程内容注意点:
    • 无需引入 less.js,无需在服务端运行

Less的注释

  • 单行注释和多行注释:
    • 单行注释,不会被编译到 .css文件中
    • 多行注释,会编译到 .css 文件中( 在 css 中仅支持 /**/ 注释)
1
2
//单行注释,不会被编译到.css文件中
/*多行注释,会编译到.css文件中*/

Less的变量

    1. 变量的定义: 和 JS 中的变量基本一致
1
2
3
4
5
6
7
8
/*定义变量*/
@width:200px;
@height:200px;
.box{
/*使用变量*/
width:@width;
height:@height;
}
  • 编译后的结果如下:
1
2
3
4
5
6
/*定义变量*/
.box {
/*使用变量*/
width: 200px;
height: 200px;
}
    1. 变量的赋值 (和 js 一样可以将一个变量赋值给另外一个变量)
1
2
3
4
5
6
7
8
/*定义变量*/
@width:200px;
@height:@width;
.box{
/*使用变量*/
width:@width;
height:@height;
}
  • 编译后的结果如下:
1
2
3
4
5
6
/*定义变量*/
.box {
/*使用变量*/
width: 200px;
height: 200px;
}
    1. 局部变量和全局变量:
    • 和 js 一样, less 中的变量也有全局变量和局部变量, 定义在 { } 外面的就是全局的变量,什么地方都可以使用, 定义在 { } 里面的就是局部变量,只能在 { } 中使用
1
2
3
4
5
6
7
8
9
/* 定义全局变量 */
@width:100px;
.box{
/*定义局部变量,优先使用就近的局部变量*/
@width:200px;
/*使用变量*/
width:@width;
height:100px;
}
  • 编译后的结果如下:
1
2
3
4
5
6
7
/* 定义全局变量 */
.box {
/*定义局部变量,优先使用就近的局部变量*/
/*使用变量*/
width: 200px;
height: 100px;
}
  • 注意定: less 中的变量是延迟加载的,写到后面也能在前面使用
1
2
3
4
5
6
7
.box{
/*使用变量*/
width:@width;
height:100px;
}
/*定义全局变量*/
@width:200px;
  • 编译后的结果如下:
1
2
3
4
5
6
.box {
/*使用变量*/
width: 200px;
height: 100px;
}
/*定义全局变量*/
    1. 同一个变量,后定义的变量会覆盖前定义的变量
1
2
3
4
5
6
7
8
@width:100px;
.box{
/*使用变量*/
width:@width;
height:100px;
}
/*定义全局变量*/
@width:200px;
  • 编译后的结果如下:
1
2
3
4
5
6
.box {
/*使用变量*/
width: 200px;
height: 100px;
}
/*定义全局变量*/

Less变量的插值

    1. 什么是变量插值?
    • 在 less 中如果属性的取值可以直接使用变量,但是如果是属性名称或者选择器名称并不能直接使用变量, 如果属性名称或者选择器名称想使用变量中保存的值,那么必须使用变量插值的格式
    1. 变量作为样式的属性名:
1
2
3
4
5
6
7
8
/*定义全局变量*/
@width:200px;
@height:height;
.box{
/*使用变量*/
width:@width;
@{height}:100px;
}
  • 编译后的结果如下:
1
2
3
4
5
6
/*定义全局变量*/
.box {
/*使用变量*/
width: 200px;
height: 100px;
}
    1. 变量作为选择器
1
2
3
4
5
6
7
8
/*定义全局变量*/
@width:200px;
@div:div;
@{div}{
/*使用变量*/
width:@width;
height:100px;
}
  • 编译后的结果如下:
1
2
3
4
5
6
/*定义全局变量*/
div {
/*使用变量*/
width: 200px;
height: 100px;
}

Less的运算

  • 和 CSS3 中新增的 calc 函数一样,都支持 + - * / 运算

  • 单位也可以写到后面,也可以两个都写

1
2
3
4
.box{
width:(200px * 0.5);
height:(200px / 2);
}
  • 编译后的结果如下:
1
2
3
4
.box {
width: 100px;
height: 100px;
}

Less的混合

  1. 什么是 less 中的混合 ( Mix in )
  • 将需要重复使用的代码封装到一个类中,在需要使用的地方调用封装好的类即可, 在预处理的时候 less 会自动将用到的封装好的类中的代码拷贝过来
  • 本质就是 ctrl+c –> ctrl +v
  1. less 中混合的注意点:
  • 如果混合名称的后面没有 (),那么在预处理的时候,会保留混合的代码
  • 如果混合名称的后面加上 (),那么在预处理的时候,不会保留混合的代码
  • 使用混合类时,也可以在后面添加 (),也可以不加 (),效果同样
1
2
3
4
5
6
7
8
9
10
11
12
13
14
.box {
/* .box 类会被编译到 .css 文件中 */
color: red;
}
.center() {
/* .center 类不会被编译出现在 .css 文件中 */
text-align: center;
}
.father {
width: 100px;
height: 100px;
.box;
.center;
}
  • 编译后的结果如下:
1
2
3
4
5
6
7
8
9
10
11
12
.box {
/* .box 类会被编译到 .css 文件中 */
color: red;
}
.father {
width: 100px;
height: 100px;
/* .box 类会被编译到 .css 文件中 */
color: red;
/* .center 类不会被编译出现在 .css 文件中 */
text-align: center;
}

Less带参数混合

    1. Less 带参数混合
1
2
3
4
5
6
7
8
9
10
11
.snail(@w,@h,@c){
width:@w;
height:@h;
color:@c;
}
.box1{
.snail(200px,200px,green)
}
.box2{
.snail(100px,100px,yellow)
}
  • 编译后的结果如下:
1
2
3
4
5
6
7
8
9
10
.box1 {
width: 200px;
height: 200px;
color: green;
}
.box2 {
width: 100px;
height: 100px;
color: yellow;
}
    1. 带参数以及默认值的混合:
    • 若传递了对应的参数,就用传递的参数
    • 若不传参则使用默认值
1
2
3
4
5
6
7
8
9
10
11
12
.snail(@w:100px,@h:100px,@c:red){
width:@w;
height:@h;
color:@c;
}
.box1{
.snail(200px,200px,green)
}
.box2{
/*给指定的形参传递数据*/
.snail(@c:yellow)
}
  • 编译后的结果如下:
1
2
3
4
5
6
7
8
9
10
11
.box1 {
width: 200px;
height: 200px;
color: green;
}
.box2 {
/*给指定的形参传递数据*/
width: 100px;
height: 100px;
color: yellow;
}

混合的可变参数

    1. arguments 不定参数
    • 可以传递任意多个参数,不传递参数也可以
1
2
3
4
5
6
7
8
.animate(...){
transition:@arguments;
}
div{
width:100px;
height:100px;
.animate(all,4s,linear,0s);
}
  • 编译后的结果如下:
1
2
3
4
5
div {
width: 100px;
height: 100px;
transition: all 4s linear 0s;
}
    1. 指定必须最少传递的参数个数
    • 若传递的参数个数,少于必须传递的参数个数,就会报错
    • 若使用了 ... ,则必须写到形参的最后面
1
2
3
4
5
6
7
8
.animate(@name,@time,...){
transition:@arguments;
}
div{
width:100px;
height:100px;
.animate(all,4s,linear,0s);
}
  • 编译后的结果如下:
1
2
3
4
5
div {
width: 100px;
height: 100px;
transition: all 4s linear 0s;
}

Less的匹配模式

混合的按需匹配模式:

  • 就是通过混合的第一个字符串形参,来确定具体要执行哪一个同名混合
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/* triangle.less */
.triangle(Down,@width,@color){
width:0;
height:0;
border-width:@width;
border-style:solid solid solid solid;
border-color:@color transparent transparent transparent;
}
.triangle(Top,@width,@color){
width:0;
height:0;
border-width:@width;
border-style:solid solid solid solid;
border-color:transparent transparent @color transparent;
}
.div{
.triangle(Top,80px,red) /* 通过第一个参数 Top 决定匹配那个类 */
}
  • 编译后的结果如下:
1
2
3
4
5
6
7
8
9
/* triangle.less */
.div {
width: 0;
height: 0;
border-width: 80px;
border-style: solid solid solid solid;
border-color: transparent transparent red transparent;
/* 通过第一个参数 Top 决定匹配那个类 */
}

混合的通用匹配模式

  • 无论同名的哪一个混合被匹配了,都会先执行通用匹配模式中的代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/* triangle.less */
/*通用匹配模式: @_ 会先执行通用匹配 */
.triangle(@_,@width,@color){
width:0;
height:0;
border-style:solid solid solid solid;
}
.triangle(Down,@width,@color){
width:0;
height:0;
border-width:@width;
border-style:solid solid solid solid;
border-color:@color transparent transparent transparent;
}
.triangle(Top,@width,@color){
width:0;
height:0;
border-width:@width;
border-style:solid solid solid solid;
border-color:transparent transparent @color transparent;
}
.div{
.triangle(Top,80px,red)
}
  • 编译后的结果如下:
1
2
3
4
5
6
7
8
9
/* triangle.less */
/*通用匹配模式: @_ 会先执行通用匹配 */
.div {
width: 0;
height: 0;
border-width: 80px;
border-style: solid solid solid solid;
border-color: transparent transparent red transparent;
}

在less中导入less

  • 在 less 文件中导入其他 less 文件
  • 导入文件时,后缀名.less可以省略
1
2
3
4
@import "triangle.less";
.div{
.triangle(Top,80px,red)
}
  • 编译后的结果如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/* triangle.less */
/*通用匹配模式: @_ 会先执行通用匹配 */
.div {
width: 0;
height: 0;
border-width: 80px;
border-style: solid solid solid solid;
border-color: transparent transparent red transparent;
}
/* 生成两个相同的类时因为 triangle.less 的 .div 类中也调用了一次 triangle */
.div {
width: 0;
height: 0;
border-width: 80px;
border-style: solid solid solid solid;
border-color: transparent transparent red transparent;
}

Less中的内置函数

  • isnumber(56px); // =>true是否含数字

  • isstring(“string”); // =>true

  • iscolor(#ffO); // =>true

  • iscolor(blue); // =>true

  • iskeyword (keyword) ; // =>true

  • isurl(url(…)); // =>true

  • ispixe1 (56px); // =true

  • isem(7.8em); // =>true

  • ispercentage(7.8%); // =>true

  • isunit(4rem,rem); // =>true是否为指定单位

  • isruleset (@rules); // =>true是否为变量

简单的变量使用

1
2
3
4
5
6
@str:"./images/1.jpg";
.box{
width:200px;
height:200px;
background:url(@str);
}
  • 编译后的结果如下:
1
2
3
4
5
.box {
width: 200px;
height: 200px;
background: url("images/1.jpg");
}

replace函数

1
2
3
4
5
6
7
8
@str:"./images/1.jpg";
/* 将 @str 变量中的1替换为2 */
@str2:replace(@str,"1","2");
.box{
width:200px;
height:200px;
background:url(@str2);
}
  • 编译后的结果如下:
1
2
3
4
5
6
/* 将 @str 变量中的1替换为2  */
.box {
width: 200px;
height: 200px;
background: url("images/2.jpg");
}

颜色饱和度

1
2
3
4
5
6
7
8
9
10
.box{
width:200px;
height:200px;
/*降低颜色饱和度*/
background:desaturate(yellow,50%);
&:hover{
/*增加颜色饱和度*/
background:saturate(yellow,50%);
}
}
  • 编译后的结果如下:
1
2
3
4
5
6
7
8
9
10
.box {
width: 200px;
height: 200px;
/*降低颜色饱和度*/
background: #bfbf40;
}
.box:hover {
/*增加颜色饱和度*/
background: #ffff00;
}

Less的层级结构

后代选择器

  • 如果在某一个选择器的 { } 中直接写上了其它的选择器,会自动转换成后代选择器
1
2
3
4
5
6
7
8
.father{
width:100px;
height:100px;
.son{
font-size:20px;
color:red;
}
}
  • 编译后的结果如下:
1
2
3
4
5
6
7
8
.father {
width: 100px;
height: 100px;
}
.father .son {
font-size: 20px;
color: red;
}

:hover

  • 这里的 & 的作用,是告诉 less 在转换的时候不用后代来转换,直接拼接在当前选择器的后面即可
1
2
3
4
5
6
7
8
9
10
.father{
width:100px;
height:100px;
.son{
font-size:20px;
&:hover{
color:red;
}
}
}
  • 编译后的结果如下:
1
2
3
4
5
6
7
8
9
10
.father {
width: 100px;
height: 100px;
}
.father .son {
font-size: 20px;
}
.father .son:hover {
color: red;
}

::before

1
2
3
4
5
6
7
8
9
10
11
.father{
width:100px;
height:100px;
&::before{
content:"子元素";
display:block;
background:red;
width:100px;
height:100px;
}
}
  • 编译后的结果如下:
1
2
3
4
5
6
7
8
9
10
11
.father {
width: 100px;
height: 100px;
}
.father::before {
content: "子元素";
display: block;
background: red;
width: 100px;
height: 100px;
}

Less中的继承

  • less 中的继承和 less 中混合的区别
    • 使用时的语法格式不同
    • 转换之后的结果不同 (混合是直接拷贝,继承是并集选择器)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
.center{
position:absolute;
left:50%;
top:50%;
transform:translate(-50%,-50%);
}
.father:extend(.center){
width:300px;
height:300px;
background:red;
.son:extend(.center){
width:200px;
height:200px;
}
}
  • 编译后的结果如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
.center,
.father,
.father .son {
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
}
.father {
width: 300px;
height: 300px;
background: red;
}
.father .son {
width: 200px;
height: 200px;
}

Less中的条件判断

  • less 中可以通过 when 给混合添加执行限定条件,只有条件满足(为真)才会执行混合中的代码

  • when 表达式中可以使用比较运算符 > < <= = >=、逻辑运算符、或检查函数来进行条件判断

比较运算符

1
2
3
4
5
6
7
8
9
/*当 widht 等于100px时,才会执行混合   等于:一个等号 */
.size(@width,@height) when (@width = 100px){
width:@width;
height:@height;
}
.box{
.size(100px,50px);
background:red;
}
  • 编译后的结果如下:
1
2
3
4
5
6
/*当 widht 等于100px时,才会执行混合   等于:一个等号 */
.box {
width: 100px;
height: 50px;
background: red;
}

逻辑或

1
2
3
4
5
6
7
8
9
/*当 widht 等于100px 或者 height 等于100px 时,才会执行混合 */
.size(@width,@height) when (@width = 100px),(@height = 100px){
width:@width;
height:@height;
}
.box{
.size(100px,100px);
background:red;
}
  • 编译后的结果如下:
1
2
3
4
5
6
/*当 widht 等于100px 或者 height 等于100px 时,才会执行混合 */
.box {
width: 100px;
height: 100px;
background: red;
}

逻辑与

1
2
3
4
5
6
7
8
9
/*当 widht 等于 100px 且 height 等于100px 时,才会执行混合 */
.size(@width,@height) when (@width = 100px)and(@height = 100px){
width:@width;
height:@height;
}
.box{
.size(100px,100px);
background:red;
}
  • 编译后的结果如下:
1
2
3
4
5
6
/*当 widht 等于 100px 且 height 等于100px 时,才会执行混合 */
.box {
width: 100px;
height: 100px;
background: red;
}

使用检验函数

1
2
3
4
5
6
7
8
9
/*当 widht 的单位是 px 时,才会执行混合 */
.size(@width,@height) when (ispixel(@width)){
width:@width;
height:@height;
}
.box{
.size(100px,100px);
background:red;
}
  • 编译后的结果如下:
1
2
3
4
5
6
/*当 widht 的单位是 px 时,才会执行混合 */
.box {
width: 100px;
height: 100px;
background: red;
}

完结