镇楼图

Pixiv:战争子

注:此blog至少建立在一定的CSS基础之上,其中选择器更加重要



〇、LESS(Leaner Style Sheets)是什么?

是CSS的预处理器,因为CSS编写起来确实特别麻烦,因此有了CSS预处理器的工具来简化编写代码时间

其他比较有名的CSS预处理还有SASS、SCSS、Stylus

引入

<link rel="stylesheet/less" href="styles.less" />
<script src="//cdnjs.cloudflare.com/ajax/libs/less.js/3.11.1/less.min.js" ></script>
<!-- 浏览器环境,引入Less.js,或者自己下载Less.js -->
npm install -g less
> lessc styles.less styles.css
<!-- Node.js环境 -->

由于LESS仅仅加了些许扩展,因此学习起来很简单,这也是为什么CSS的blog还没写完我先写LESS的情况。不必担心兼容性,LESS几乎支持一切浏览器

问题一:如果在客户端环境下使用或多或少必然会有一定上性能的消耗

问题二:LESS由于使用了Ajax必须必须在http(s)协议下使用,直接本地文件执行js文件是不会有任何效果的!!!!!

Koala

可以下载Koala用于将Less文件转译成css文件,由此可以使用生成的css文件而不必使用less文件也能避免上述所说的问题

但是需要注意LESS在Koala里的版本是非常低的,为了避免因版本导致的错误,建议您安装nodejs后安装less,具体安装步骤这里就不再阐述了

LESS文件编写

首先创建个less后缀的文件,然后和CSS一样就可以开始写LESS加持的代码了

但需要注意每个.less文件是独立编译的,其中的任何定义的东西都是不可相互访问的,也就是1.less中定义的变量不可以在2.less中访问


一、变量

尽管在CSS3中也存在变量机制,但其支持可能并不如LESS

变量定义属性值

变量可以去定义属性值,以【@变量名】的形式定义,调用属性值也是【@变量名】

@width: 10px;
@height: 50px;

.father {
    width: @width;
    height: @height;
}

个人理解:@指针

变量本身是通过@去定义的,其中@可以理解为指针

对上一个例子稍加改动可以很直观地说明这个问题

@width: 10px;
@height: 50px;

.father {
    width: width;
    height: @height;
}

当我用koala编译后它的结果如下图

其中加了@的被解成了50px,没加@的就是其原样

在下面变量定义变量能感受这种类似于指针的用法

指针与变量赋值

变量同样可以作为其他变量的变量

@color1: grey;
@color3: color1;
//不加@就是其本身

p{
    color: @@color3;
    //color3就是color3
    //@color3被解成了color1
    //@@color3被解成了grey
}

但是LESS似乎只支持到两层@,当博主尝试@@@时报错了

在理解变量的本质后应该知道如何去赋值变量

@color1: grey;
@color3: @color1;
//加@就是其属性值从而完成赋值操作

p{
    color: @color3;
}

个人理解:$解引用(v3.0.0)

在新版本3.0.0下可以使用$符号来解引用一个要作为样式的属性

在某些情况下可能更加节省代码量。

我个人认为这种语法适用于“同类属性”的情况,所谓同类属性是指功能性一样但应用范围不同,如下例的color、background-color都是用于颜色设置只不过一个是文字一个是背景罢了

div {
    margin: 0px;
    padding: $margin;
    color: #fff;
    background-color: $color;
    //解引用无需定义新的变量
}

基于上面@假设为指针的理解,这里我理解为解引用,但理解归理解,实际操作和之前指针一样无法实现理解上的语法

变量定义属性名和部分属性名(v1.6.0)

除了属性值以外变量还可以定义很多内容,其中只要不是去定义属性值或是变量的,在调用时必须以【@{变量名}】的形式去调用

LESS不像正统语言一样有严格的语法规范,有些看上去可能符合猜想的语法都会报错

@p1: color;

.father {
    @{p1}: red;
}

此外还可以去定义部分属性名,很多CSS属性会用-符号区分这时候可以通过LESS这样定义

@v: left;

.div1 {
    margin-@{v}: 0;
}

变量定义选择器(V1.4.0)

@firbox: father;
@element: a;

.@{firbox} > @{element}[data-v="1"]:visited {
	color: red;
}

变量定义url(的一部分)(v1.4.0)

由于url网址部分一般都是会有相同的前缀部分,也可以定义url字符串在url里使用

@images: "../images";

html {
    background: url("@{images}/1.jpg");
}

变量作用域(Lazy evaluation)

只要保证调用变量时能从当前层级往上能找到即可

@{selector} {
    @{attr}: @value;
    @value: red;
}
@attr: color;
@selector: p;
//虽然定义在下
//但能从调用处往上寻找时能搜查到此层级

另外这种搜查机制也对于同名变量来说符合就近原则

p {
    @v: #123;
	color: @v;
    @v: #456;
    //结果为#456
    //它会优先搜查一遍
    //搜查后#456当然覆盖了#123
}
@v: #789;
//由于调用那一层已经搜查到了
//因此无需向上搜查此层

二、属性值运算

赋值

上面有讲过便不再赘述

@a: 10;
@b: @a;

空格附加

比如CSS中margin多个属性值来说是通过空格来间隔开的,LESS提供这样一个机制去实现多个属性值空格相加

通过+_符号以空格形式附加属性值

@v1: 10px;
@v2: 20px;
@v3: 30px;
@v4: 40px;
.div1{
    /*已忽略其他必要属性*/
    margin+_: @v1;
    margin+_: @v2;
    margin+_: @v3;
    margin+_: @v4;
}

.div2{
	margin: @v1 @v2 @v3 @v4;
    //虽然也能通过这种方式附加
    //这与后面的函数相关联
    //比如设定一个函数附加属性值
    //这样的机制无法实现而+_可以
}

逗号附加

还有一类属性值必须要通过逗号隔开,LESS是通过+符号以逗号形式附加属性值

这里不作演示了

简单运算

对于Less而言它可以进行一些简单的运算,当然在Less内置函数中还内置大量数学函数可以实现非常复杂的运算

@size: 10;
@o1: @size + 5;
@o2: @size - 5;
@o3: @size * 5;

div {
	d1: @o1;
	d2: @o2;
	d3: @o3;
}

三、嵌套(Nesting)

嵌套

嵌套是非常常用的工具,可以使大量CSS难以看清楚的结构,在Less中变得显而易见

father {
    display: flow-root;
    .first,.second {
        width: 400px;
        height: 200px;
    }
    .first {
        margin-bottom: 100px;
        background: purple;
    }
    .second {
        margin-top: 200px;
        background: green;
    }
}
//比如这里显而易见的,father中套了first、second
//而CSS处理的话只会分开,当数量足够多时便很难分清结构了

引用父元素

嵌套虽然实现了父类→子类的,但无法实现子类→父类,&提供了从子类→父类的功能

这一般用于类、复杂运算、属性值选择器或是伪类,如下例只需要&即可实现不同伪类的情况,同样其结构也更加清晰

a {
    font-size: 20px;
    background: pink;
    &:link {
        color: red;
    }
    &:visited {
        color: green;
    }
    &:active {
        color: hotpink;
    }
    &:hover {
        color: blue;
    }
}

所谓引用是真的完全引用,不会有太大的语法限制

也会有这种形式的LESS代码

.area {
    &-1 {}
    &-2 {}
    //类
    & &[data-v1="3"]:hover{}
    .father &{}
    //假设.father盒子嵌套.area盒子
    //那么可以实现这种嵌套的样式
    //复杂运算
}
//通过这种方式可以很好地集成代码

你可能会担心还会生成一个.area的父类,但实际上LESS会进行优化,只要你的选择里没有任何样式那么它就不会生成此类。.area下面全都是选择器,并不是具体的样式,因此它不会生成.area这一个父类,可以放心大胆地使用这种代码

引用父元素的组合

上面阐述了引用父元素下其子元素能够如何如何之类的,但是其父元素也是可以参与运算的,这样会导致更加灵活的嵌套,但目前我个人没找到这种实际应用的场景

.a,.b > .c{
    & & {}
}

因为CSS除了组合运算以外不管是伪类也好属性选择器也好,它本质上都只是一个选择器,但组合选择器是多个。

核心在于组合运算,上面例子仅仅是组合了.a和.b > .c两个选择器,使用& &{}会是什么?

LESS会把每一个&尝试组合中的所有选择器

结果会是

.a .a,
.a .b > .c,
.b > .c .a,
.b > .c .b > .c {
	/*某个样式*/
}

这里简单用数学计算下,假设LESS代码里定义选择器时有n个&符号,而父类组合的有m个选择器,那么其组合后总共会去组合\(m^n\)个选择器


四、混合(Mixins)

函数

这里博主统一称为函数,一个样式规则集可以当作函数。函数内部可以写好一个样式模板,某个属性需要时调用即可

但是需要注意函数的命名必须是类选择器或是id选择器的命名

.a , #b {
    //既可以当作某个样式渲染(如果HTML中满足的话)
    //也可以当作函数来调用
    color: red;
    font-size: 19px;
}

.father {
    #b();
}

由于版本原因,调用的时候()是可选的,在未来版本可能会被删除

.a , #b {
    color: red;
    font-size: 19px;
}

.father {
    .a;
	//不用()也能生效
}

参数

上面的语法也会当作样式来渲染,但有时候可能就想当作函数,这时候只需要在函数后加上()即可

.c() {
    //不会生成.c的CSS代码
    color: red;
    &:link {
        color: red;
    }
    &:visited {
        color: green;
    }
    &:active {
        color: hotpink;
    }
    &:hover {
        color: blue;
    }
}

a {
    .c;//此时&引用是a
}

此外可以设置形参来传递实现更复杂的操作

.color(@color){
    color: @color;
}
.fontsize(@size: 16px){
    //可以设置默认值
    font-size: @size;
}

p {
    .color(black);
    //未设置默认值必须填写参数
	.fontsize();
}

在写默认值有时并不止一个属性值

如果多个属性值是要用,分隔的,此时可以用;分隔参数

如果多个属性值是用空格分隔的,可以用,也可以用;分隔参数

.a(@border:3px solid red ; @margin:0 auto){
    //用;分隔参数
	border: @border;
	margin: @margin;
}

div {
	.a;
}

调用参数时可以指定形参名,这时调用无需注意顺序

.a(@border:3px solid red;@margin:0 auto){
  border: @border;
  margin: @margin;
}
div{
  .a(@margin:10%);
}

函数的嵌套

由于嵌套语法的存在,函数也是可以嵌套的

LESS提供了三种等价性的调用方式

分别是.father > .son,.father .son和.father.son

这三种形式没有任何区别,它会调用所有下一级子函数的样式

.a(){
    color:blue;
    font-size: 18px;
    .b(){
        padding: 0;
        color:red;
        .b(){
            margin: 0;
        }
    }
    .b(){
        background: black;
        color:blue;
        //LESS输出并不会去覆盖样式
        //因此结果里会有两个color
    }
}

.div1 {
	.a.b;
}

.div2 {
	.a > .b .b();
}

调用的函数只会在这一层而不会出现其父类或是子类的函数,若要使用子类的函数必须去调用才行

守卫(Guard)

在LESS中when的保护条件称为是Guard,其中只有满足when条件才可执行,不满足不会被执行

.a() when(true){
	color: red;
}
p {
    .a;
}

.b() when (@mode = 1){
	color: blue;
}
p {
    @mode: 2;
    .b;
    //@mode为2不满足
    //因此会拒绝.b()函数调用
}

在1.5以后守卫机制不仅可以适用于函数还可以适用于选择器上

@my-option: true;
& when (@my-option = true) {
    //备注:若不存在&则不会有父元素
    //但可以用不存在的元素专门用作条件语句
  	button {
    	color: white;
  	}
  	a {
    	color: blue;
  	}
}

@arguments

@arguments可以将所有参数同时传递

.pos(@top: 0; @right: 0; @bottom: 0; @left: 0) {
	margin: @arguments;
	padding: @arguments;
    //同时传递了@top @right @bottom @left
    //且参数之间是空格附加的
}
div {
	.pos(50px,30px,50px,20px);
}

@rest以及不定参数

用...可以表示不定参数,@rest可以指定剩余的可变参数

但CSS的属性值绝大部分都是有限个,因此应用场景可能不多

.minin()){}//无参
.minin(@rest...){}//任意个参数
.minin(@a){}//无参或一个参数
.minin(@a;@rest...){}//任意个参数
.minin(@a: 1;@rest...){}//至少一个参数

模式匹配

LESS的函数是只要满足就会实现,因此可以设定一个常量作为形参

当满足该常量时便会执行,否则不会执行,可以作为不同情况的函数

.mixin(dark; @color) {
  color: darken(@color, 10%);
}
.mixin(light; @color) {
  color: lighten(@color, 10%);
}

div {
  .mixin(light, #888);
   .mixin(dark,#aaa);
    //执行drak的.mixin函数
}

实现分支结构

LESS中是通过保护条件来实现分支语句的,如下面实现采用更大宽度的代码

.max(@a; @b) when (@a > @b) { width: @a }
.max(@a; @b) when (@a < @b) { width: @b }

此外条件之间也可以使用and、or、not这三类逻辑运算符

对于函数的返回值博主认为应用场景不多故此忽略,详细可在官网中查看器语法

至于循环结构博主认为只需要在第六节提到的each方法即可实现,无需本身的循环结构

实现哈希表(v3.5.0)

在3.5.0的版本中变量可以去存储函数,基于这个机制可以实现哈希表

#Font(){
    //定义#Font实例内置size、color数据
    .size(){
        style1: 12px;
        style2: 15px;
        style3: 18px;
    }
    .color(){
        style1: black;
        style2: white;
        style3: grey;
    }
}

p{
	@f-c: #Font.color();
    color: @f-c[style1];
	font-size: #Font.size()[style3];
	//可以直接通过函数去索引相当于哈希表
}

选择器、属性名作为参数

我之前用less确确实实有这么一个需求,需要针对不同类名某些相同属性设定不同的属性值,那么可以如下实现

.f(@selector,@value){
    //@selector作为类选择器参数
    .@{selector} {
        font-size: @value;
    }
}
.f(m1,12px);
.f(m2,14px);
.f(m3,16px);

此时可以将选择器作为一个形参来设置属性值,属性名同理这里不再赘述

函数作为参数

函数本身也是可以作为形参对象的,这在封装某些代码时会非常有用

.media(@rules1,@rules2) {
	@media screen and (max-width: 799px) {
		@rules1()
	}
  	@media screen and (min-width: 800px)  {
      	@rules2();
  	}
}
.f(){
	font-size: 18px;
}
.g(){
	font-size: 24px;
}
* {
	.media(.f(),.g());
    //备注:必须加()否则出错
}

五、扩展(Extend)

Less中有一个特殊的伪类——extend,它用于实现组合运算

因为有时仅仅是嵌套,混合并不能完全满足开发需求,扩展适用于选择器组合运算时的某些相同样式

extend伪类

下例将会先生成nav选择器,再生成nav, .inline选择器

nav {
  &:extend(.inline);
  background: blue;
}
.inline {
  color: red;
}

extend内同样可以有多个选择器的组合形式

.div1:extend(.f, .g) {}
//extend参数组合等价于下面两行语句

.div1:extend(.f) {}
.div1:extend(.g) {}
//LESS允许多个extend但效果仍然是组合
//下面的代码与上面的是等价的
.div1 :extend(.f) :extend(.g) {}
//备注:extend允许与选择器之间存在空格

同样地除了内部参数的组合还可以有父选择器的组合

pre:hover, .some-class {
  &:extend(div pre);
}
//等价于如下代码
pre:hover:extend(div pre),
.some-class:extend(div pre) {}

extend伪类可能会与其他伪类相互结合,但LESS的extend伪类必须位于最后,否则报错

pre:hover:extend(div pre).nth-child(odd) {}
//报错,extend伪类必须位于最后

精确匹配

extend内的选择器是精确匹配的,附加任何运算形式都不会计算在内

*.class {
  	color: blue;
}
.noStar:extend(.class) {
    //不存在.class选择器
    //不会有任何组合效果
    color: red;
} 

all选项

扩展虽然是精确匹配的,但all参数可以解除这种精确性

使用all参数匹配会改成匹配有关参数的所有选择器,并且会进行相同的运算

.div:extend(.other all) {
    //组合有关.other的所有选择器
	//且会进行相同运算的组合
}
.other {
    //会去精确匹配
	color: blue;
}
*.other {
    //附上了运算
    //得到的组合会是*.div, *.other
	margin: 0 auto;
}
.other > .e {
    //同理组合是.div > .e, .other > .e
	padding: 0;
}
.father{
    //同理组合是.father .div,.father .other
	border-style: dashed;
	.other {
		overflow: hidden;
	}
}
.other {
	//同理组合是.div .sub,.other .sub
	clear: left;
	.sub {
		display: flow-root;
	}
}

缺陷

目前extend组合语法并不支持在参数内使用变量,因为语法角度来说是有可能会用到extend内为变量去动态地组合

但是外部的选择器是可以使用变量替代的

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

六、其他

@import声明(1.4.0)

与CSS不同的是Less的@import可以随意在任意地方声明

Less可以去调用其他样式文件,调用后其文档原本全局变量的作用域会改成当前文档

@pref: "../lessheader";

p {
    font-size: @size2;
}

@import "@{pref}/header1.less"
/*假设@size2在header1.less中
  这里提供了一种类似于头文件的声明方式
  可以去管理Less的变量、函数
*/

还有其他一部分内容,但属于提高less的可扩展性,这里就不做过多介绍了

数学函数

备注:CSS有单位一说,但大部分数学函数转换后依然是原本单位

函数 说明
pi() 返回圆周率π
abs(x) x取绝对值
ceil(x) 对x上取整
floor(x) 对x下取整
percentage(x) 将x转成百分数,如0.15转成15%
round(x,decimal) 对x第decimal位四舍五入
decimal可省略默认为0即整数四舍五入
如round(1.8877,2)会返回1.89
mod(a, b) 返回a%b
sqrt(x) x取根号
pow(base, exp) 返回base的exp方
sin(x),cos(x),tan(x) 三角函数,详细见备注
asin(x),acos(x),acot(x) 反三角函数,详细见备注
min(v1,...),max(v1,...) 至少输入1个参数,返回最小/大值

备注:LESS对三角函数支持三类单位,分别是弧度制、角度制、百分度制,但返回值统一是弧度制

sin(2);//弧度制
cos(60deg);//角度制
tan(100grad);//百分度制

布尔值

Less以函数形式支持boolean数据类型

创建条件如下

@flag: boolean(/*条件*/@a > 5);
@a: 10;

if函数

虽然有guard机制实现分支,但也以函数形式提供了分支语句

格式为【if(条件,true时执行语句,false时执行语句)】

其中可以忽略最后的false时执行的语句

若要实现if-else的结构需要在false处再嵌套if语句

@bg: black;
@bg-light: boolean(luma(@bg) > 50%);

div {
  background: @bg; 
  color: if(@bg-light, black, white);
}

字符串常用函数

函数 说明
e(str) 删除str的分号
如具体处理时采用字符串
但调用却不是字符串那么可以使用此方法
%(str,arg,...) 格式化字符串,详细见备注

备注:可以使用%函数来格式化字符串,其中占位符有分大小写,其中小写会保持特殊字符的原样,而大写会将特殊字符转成UTF-8编码形式,如空格会转成%20,/会转成%2

由于使用了%表示占位符,若要表示%本身需要写成%%

占位符 说明
%a,%A,%d,%D 与其他语言不同
它可以被任何类型替代而不是专指某类数据类型
%s,%S 上一方式在表达字符串时存在问题
它会将表述字符串的引号
使用这一类占位符可以忽略字符串的引号
format-a-d-upper: %('repetitions: %A file: %d', 1 + 2, "directory/file.less");
//存在问题,由于不是%s会带来引号

数组

Less支持一个变量去定义数组,在某些情况可能有较好的效果

比如设计网站后将所有会用到的颜色集成一个数组

@Color: "white" "grey" "green";
//用逗号分隔或空格分隔即可定义数组
//但需要统一分隔符,除非属性值的表述需要分隔符
数组相关函数 说明 版本说明
length(arr) 返回数组元素个数
extract(arr, index) 索引,返回arr第index个元素
备注:下标从1开始
range(start,end,step) 详细见下节内容 v3.9.0
each(arr, rules) 详细见下节内容 v3.7.0
@Color: "white" "grey" "green";
p {
    color: extract(@Color,2);
    //设置为灰色,但这里存在些问题
}

高版本功能:实现循环结构(v3.9.0)

数组新方法特别好用,蓝桥杯web比赛的less只支持到2.x的版本可惜了

range函数用于生成数组,each用做循环

range(2,5,2);//返回数组元素2 4
range(3);
//也可以省略初值和步长,默认为1
//返回数组1 2 3

each函数用来迭代

each(@selector, {
    @{selector}{
        margin: 0 auto;
    }
});
//第一个参数为数组
//第二个参数为函数可以匿名定义

解析获取属性值

Less提供了一类函数可以通过某些值来获取相应属性值,比如只要知道图像的url就可以获取其大小

函数 说明 版本说明
color(str) 字符串转成颜色值
image-size(str) 根据字符串表述的url返回相应文件的大小
备注:同时返回宽度和高度可以用数组来接收
2.2.0
image-widtht(str) 同上但只返回宽度 2.2.0
image-height(str) 同上但只返回高度 2.2.0
unit(number,unit) ①若省略unit作用是返回其不带单位的数字本身,在运算上不会出现混乱,如unit(1000ms)返回为1000
②不省略unit则会去设置单位,不管原本number有没有单位都会替换,如unit(10px,cm)返回10cm
get-unit(number) 返回number的单位,若无单位不会返回任何内容
该函数可以结合unit进行较灵活的单位转换
convert(number,unit) 将number的单位及数值进行等价替换
unit纯粹是改变单位,但convert还会换算数值
convert限定了必须在某一组单位进行转换否则不会产生任何效果
①长度:m, cm, mm, in, pt, pc
②s, ms
③角度:rad, deg, grad, turn
convert(9s, "ms");
//在时间组内等价替换成9000ms
@Color: "white" "grey" "green";
p {
    color: color(extract(@Color,2));
    //直接从数组获取字符串但它并不是颜色值
    //通过color函数转成可用的颜色值
}

判定类型

Less提供一组函数用于判定不同的数据类型

函数 说明
isnumber(x) 判定是否为数值
isstring(x) 判定是否为字符串
iscolor(x) 判定是否为颜色值
isurl(x) 判断是否为url
ispixel(x) 判断其单位是否为px
isem(x) 判断其单位是否为em
ispercentage(x) 判断其单位是否为%
isunit(x,unit) 判断其单位是否为unit
isruleset(x) 判断是否为规则集
由于变量可以表述任何内容
导致有时并不能直接看出一个变量代表着什么

备注:严格来说上面的函数准确名字叫做规则集,函数是指带返回值的

但这里博主自作主张地称其为函数



参考教程

LESS

尚硅谷

posted on 2022-05-08 10:10  摸鱼鱼的尛善  阅读(131)  评论(0编辑  收藏  举报