Less
介绍
less对于css,很像jquery对于js,让原生内容简化,代码写的少,但是实现的功能却更多。
同时,less的表达,也更像js 。比如变量,嵌套,封装,函数,映射,作用域等等。
所以,学习的时候,可以结合css和js来学习less,更容易理解。同时,在本篇中,我也会不断提醒这一点。
官网
https://less.bootcss.com/
less对于css样式的表达,是通过各种各样的符号来实现的。
比如@ , & , ( ) , { } , [ ] , $等,这让less更像css和js封装的混合体。
本篇就以符号位主线,对less内容进行整理。
安装
less.js是一个js库,需要在node环境下安装和使用。
// node环境下安装
npm install less -g
#or:
yarn global add less
less不能直接被浏览器识别,需要转换为css样式,这要用到less-loader进行编译,
这里有个最大的坑,就是要注意less-loader的版本,一般使用5版本。
npm install less-loader@5
#or:
yarn add less-loader@5
目前,less主要在前端框架中使用,还需要一些额外的webpack配置:
Vue-cli中使用less :点击查看
React中配置less :点击查看
嵌套
less可以像dom结构一样嵌套书写:
比如当前一组dom结构
<div class="box">
<div class="box1"></div>
</div>
<div class="box2"></div>
用less给该组dom写样式,就可以这样写:
.box {
width: 100px;
heigth: 100px;
.box1 {
width: 50px;
height: 50px;
}
}
.box2 {
width: 100px;
heigth: 100px;
}
这样就表示了.box和.box1类样式的父子关系,.box和.box2的兄弟关系。
如果这里把.box2写到.box中,.box2的样式是不会生效的,因为结构错乱了。
注释
注释,分为注释单行和注释多行。这和js的注释方法是一致的。
// 注释单行用//表示
// @width: 100px;
// 注释多行,用/**/表示
/*.box {
width: @width;
}*/
@
普通变量
// 定义一个宽度变量
@width: 100px;
// 使用变量
.box {
width: @width; // width: 100px;
}
// 定义一个新变量,值是@width
@height: @width;
.box {
height: @height; // height: 100px;
}
// 这一点,和js是一致的。
变量插值-选择器
@one-class: btn;
.@{one-class} {
width: 100px;
}
// 编译结果为
.btn {
width: 100px;
}
变量插值-urls
@urls: "../images";
.box {
background: url("@{urls}/huaban.png");
}
// 编译结果为
.box {
background: url("../images/huaban.png");
}
这里还有个常用的用法。
比如,当前页面中需要用到很多次设置背景图片,图片的地址相同,但是名称不同,
就可以结合mixins 这样来做:
.setbg(@url) {
background-image: url("../images/@{url}");
}
假如此时.box元素需要设置一个“huaban.png”的图片:
.box {
.setbg("huaban.png");
}
// 编译结果为:
.box {
background-image: url("../images/huaban.png");
}
变量插值-import
@themes: "../../src/themes";
@import "@{themes}/tidal-wave.less";
// 编译结果为
@import "../../src/themes/tidal-wave.less";
变量插值-属性
@property: color;
.widget {
@{property}: #0ee;
background-@{property}: #999;
}
// 编译结果为
.widget {
color: #0ee;
background-color: #999;
}
可变变量
就是通过@的叠加,实现深层次的变量赋值
@primary: pink;
.box {
@color: primary;
.box1 {
color: @@color; // color: pink;
}
}
延迟计算
less中的变量,可以先使用,后定义和赋值。
.box {
color: @primary;
}
@primary: pink;
// 编译结果为
.box {
color: pink;
}
这里有一个类似于js的作用域和变量提升的问题,
一个{ }就相当于一个局部作用域,
当同一个变量名称被多次赋值,那么该变量最终的值,
就是在该作用域下的最后被赋予的那个值。
比如:
@var: 0;
.class {
@var: 1;
.brass {
@var: 2;
three: @var;
@var: 3;
}
one: @var;
}
// 编译结果为
.class {
one: 1;
}
.class .brass {
three: 3;
}
这有点像css的自定义属性,
顺便延申阅读:css自定义属性
$ 变量属性
$会把已经存在的属性当作变量来使用。
通过属性,获取到对应的属性值。
比如:
.box {
width: 100px;
height: $width; // height: 100px;
}
// or:
.box {
width: 100px;
.box1 {
width: $width; // width: 100px;
}
}
变量属性同样存在同个作用域的取值问题:
它会使用该作用域内的最后一个该属性的值作为自己的值。
.box {
color: blue;
.box1 {
background-color: $color; // background-color: pink;
}
color: pink;
}
Mixins
mixin,就是混合,或者混入。在整个前端的内容中,会时不时的看到这个概念。
它的作用是,把一些公用的内容抽取出来进行封装,供别的内容调用。
别的地方来调用,就会把这些公用的内容插入到调用元素的内容中,这个过程,就叫混合。
基础mixins
比如我们定义一个.bordered类:
.bordered {
border: 1px solid red;
border-radius: 4px;
}
现在.box类中也要用到.bordered里的属性,就可以在.box中调用.bordered:
.box {
width: 100px;
height: 100px;
.bordered();
}
此时.box经过编译,就会变成:
.box {
width: 100px;
height: 100px;
border: 1px solid red;
border-radius: 4px;
}
分组和封装
当混入样式多了之后,需要对这些样式进行分组,方便分开调用。
而且为了混入样式表达不那么混乱,还需要把它们封装在一起。
比如有下面两个mixins样式:
.btn {
width: 70px;
height: 30px;
border: 1px solid #333;
outline: none;
}
.colors {
color: #fff;
background-color: red;
}
把上面两个mixins都封装在==#mixins==类下面:
#mixins() { // 注意这里有个(), 并且下面的内容之间没有分号或者逗号
.btn {
width: 70px;
height: 30px;
border: 1px solid #333;
outline: none;
}
.colors {
color: #fff;
background-color: red;
}
}
接下来,.box类中需要使用到.colors中的所有样式,那么就可以这样使用了:
.box {
width: 100px;
height: 100px;
#mixins.colors();
}
映射[]
从less@3.5开始,还可以把单个属性变量放入mixins中。
#colors() {
primary: blue;
secondary: red;
}
// 在.box类中使用mixins中的属性:
.box {
color: #colors[primary]; // color: blue;
background-color: #colors[secondary]; // background-color: red;
}
带参数的mixins
创建一个mixins:
.set-color(@my-color) {
color: @my-color;
}
使用:
.box {
.set-color(#fff);
}
// 编译为
.box {
color: #fff
}
如果是多个参数,要用==;==隔开。这一点注意和函数的区别。
.set-color(@color1; @color2; ...) {
...
}
还可以给参数设定默认值:
.set-color(@my-color: pink) {
color: @my-color;
}
.box {
.set-color(); // 不传参的时候,就执行默认值
}
// 编译为
.box {
color: pink;
}
和插值变量结合的带参数的mixins 可以参考插值变量 urls中的例子。
mixins中存放选择器
存放普通选择器:
.mixins {
.box1 {
color: pink;
}
}
.box {
.mixins();
}
// 编译为
.box .box1 {
color: pink;
}
和&结合:
.mixins {
&:hover {
background-color: pink;
}
}
.btn {
.mixins();
}
// 编译为
.btn:hover {
background-color: pink;
}
@arguments
当某个属性会用到所有参数时,把参数都写一遍会很麻烦, 可以直接用@arguments代替。
.shadow(@x: 0; @y: 0; @blur: 2px; @color: #000) {
box-shadow: @arguments;
}
.box {
.shadow();
}
// 编译为
.box {
box-shadow: 0 0 2px #000;
}
!important
当!important作用到mixins的执行时,会给它里面的所有属性都加上!important
.my-color {
color: pink;
font-size: 16px;
}
.box {
.my-color() !important;
}
// 编译为
.box {
color: pink !important;
font-size: 16px !important;
}
函数mixins
类似于vue的computed,就是为了得到某个值而创建
.averge(@x, @y) {
@result: ((@x + @y) / 2); // 取平均值
}
.box {
width: .averge(16px, 50px)[@result];
}
// 编译为
.box {
width: 33px;
}
when
用来完成判断和循环,类似js的when语法(写法上会有区别)。
// 创建一个带when的mixins
.generate-columns(@n, @i: 1) when (@i =< @n) {
.column-@{i} {
width: (@i * 100% / @n);
}
.generate-columns(@n, (@i + 1));
}
// 使用
.generate-columns(4);
// 输出结果
.column-1 {
width: 25%;
}
.column-2 {
width: 50%;
}
.column-3 {
width: 75%;
}
.column-4 {
width: 100%;
}
判断相等
.number-check(@a) when (@a = 5) { ... }
判断大小
.max(@a; @b) when (@a > @b) {width: @a}
且判断
.mixin(@a) when (@a > 0) and (@a < 5) { ... }
或判断
.mixin(@a) when (@a = 1) , (@a = 3) { ... }
非判断
.mixin(@a) when not (@a < 0) { ... }
&
在less嵌套结构中,用&表示用{ }包裹住当前选择器的那个选择器。
.box {
&.box1 {
width: 100px;
}
}
此时,当前选择器是.box1,包裹住.box1的是.box,所以&就表示.box
而&.box1就是css中的.box.box1,即同时具有.box和.box1的那个元素
和伪类结合使用:
.btn {
color: #fff;
&:hover {
color: pink;
}
}
此时,当前选择器是:hover,包裹住:hover的是.btn,所以&就表示.btn
.btn:hover就表示.btn元素悬浮时的样式
/************************************/
// 清除浮动
.clearfix {
display: block;
zoom: 1;
&:after {
content: " ";
display: block;
font-size: 0;
height: 0;
clear: both;
visibility: hidden;
}
}
既然&能够作为父级选择器存在,那么它就可以这样使用:
.box {
width: 100px;
&1 {
width: 50px;
}
}
// 相当于:
.box {
width: 100px;
.box1 {
width: 50px;
}
}
+ - * /
计算以加减法为主。
单位相同的加减计算,会先计算出数字,然后给数字加上该计量单位,得出最终结果:
@width: 20px + 50px; // 70px
less的计量单位遵循以左为主
单位不同的加减计算,如果有能转换成相同单位的,则先转换为相同单位,再进行计算;
如果不能转换成相同单位的,则先计算出数字,再把左边第一个计量单位作为最终的计量单位。
@long-unit: 5cm + 10mm; // 6cm
@new-unit: 5 - 2cm - 5mm; // 2.5cm
@other: 2 + 5px -3cm; // 4px
对于乘除运算,以简单计算为主。毕竟复杂的单位换算,意义不大。
@base: 5% * 2; // 10%
calc()
执行一些简单的计算。
@leng: 50vh/2;
.box {
width: calc(50% + (@leng - 20px));
}
~
是转义符。符号后面的内容,在编译时,会保持原样进行输出。
~"(min-width: 768px)" 会被编译为 (min-width: 768px)
less@3.5版本后,有直接简写方式,这种转义符号就不需要了。
导入
导入.css文件
@import 'demo.css'; // 分号不要忘记写
导入.less文件
@import 'demo.less';
// 当导入.less文件时,.less后缀可以省略
@import 'demo';
内置函数
if
语法:
if(判断条件, a, b)
// 如果判断条件得到的结果为true,则执行a值。 否则,执行b值
// 类似于js中的if(判断条件) {return a} else {return b}
如果判断条件只有1个,那么就用==()==包裹住判断条件。不然可能会在某些less版本中报错。
.box {
width: if((2 > 1), 10px, 20px);
}
// 编译为
.box {
width: 10px;
}
if中的且判断:
if((true) and (2 > 1), a, b)
if中的或判断:
if((2 > 1) or (3 > 2), a, b)
if中的非判断:
if(not (true), a, b)
escape
用于url编码,通俗点讲就是把特殊符号转换成乱码的形式。
escape('a=1')
// 编码结果:
a%3D1
e
用于去除引用,简单说就是去掉引号,引号中是啥就输出啥
@mscode: "ms:alwaysHasItsOwnSyntax.For.Stuff()"
filter: e(@mscode);
// 结果
filter: ms:alwaysHasItsOwnSyntax.For.Stuff();
% format
==%(string, arguments …)==用于格式化字符串。
第一个参数是一个包含占位符的字符串。占位符以百分号 % 开头,
后面跟着字母 s 、S 、d 、D 、a 或 A 。后续的参数用于替换这些占位符。
如果你需要输出百分号,可以多用一个百分号来转义 %% 。
使用大写的占位符可以将特殊字符按照 UTF-8 编码进行转义。
此函数将会对所有的特殊字符进行转义,除了 ()'~! 。空格会被转义为 %20 。
小写的占位符将原样输出特殊字符,不进行转义。
format-a-d: %("repetitions: %a file: %d", 1 + 2, "directory/file.less");
format-a-d-upper: %('repetitions: %A file: %D', 1 + 2, "directory/file.less");
format-s: %("repetitions: %s file: %s", 1 + 2, "directory/file.less");
format-s-upper: %('repetitions: %S file: %S', 1 + 2, "directory/file.less");
// 格式化结果:
format-a-d: "repetitions: 3 file: "directory/file.less"";
format-a-d-upper: "repetitions: 3 file: %22directory%2Ffile.less%22";
format-s: "repetitions: 3 file: directory/file.less";
format-s-upper: "repetitions: 3 file: directory%2Ffile.less";
replace
用来替换字符串中的字符。
有4个参数,原字符串,要被替换的字符 ,用来替换的字符串 , 匹配规则
replace("Hello, Mars?", "Mars\?", "Earth!");
replace("One + one = 4", "one", "2", "gi");
replace('This is a string.', "(string)\.$", "new $1.");
replace(~"bar-1", '1', '2');
// 替换结果
"Hello, Earth!";
"2 + 2 = 4";
'This is a new string.';
bar-2;
@list
列表,数组。
@list: "banana", "tomato", "potato", "peach";
n: length(@list);
// 结果
n: 4
extract
获取list列表中的数据
@list: apple, pear, coconut, orange;
value: extract(@list, 3);
// 结果
value: coconut;
range
获取范围值。
有3个参数:
开始的值 :比如1或者1px,可选,默认为1
结束的值 :比如5或者5px,必须
增加幅度 :每次增加的值,可选,默认为1
value: range(4); // 从1开始,每次增加1,一直增加到4
// 结果:
value: 1 2 3 4;
value: range(10px, 30px, 10); // 开始值为10px,结束值为30px,每次增加10
// 结果:
value: 10px 20px 30px;
each
枚举,遍历
有2个参数:
list :可枚举对象,如数组,对象等
枚举规则 :枚举时执行的内容
@selectors: blue, green, red;
each(@selectors, {
.sel-@{value} {
a: b;
}
});
// 编译为:
.sel-blue {
a: b;
}
.sel-green {
a: b;
}
.sel-red {
a: b;
}
如果list是对象
@set: {
one: blue;
two: green;
three: red;
}
.set {
each(@set, {
@{key}-@{index}: @value;
});
}
// 结果:
.set {
one-1: blue;
two-2: green;
three-3: red;
}
ceil
类似于js的Math.ceil()
ceil(2.4)
// 结果
3
floor
类似于js的Math.floor()
floor(2.4)
// 结果
2
percentage
把数字变成百分比
percentage(0.5)
// 结果
50%
round
四舍五入。有2个参数:
1. 数字
2. 要保留的小数点后几位,默认为0,即结果取整数
round(1.67)
// 结果
2
round(1.67, 1)
// 结果
1.7
sqrt
开平方,取正数平方根
sqrt(25cm)
// 结果
5cm
abs
取绝对值
abs(25cm)
// 结果
25cm
abs(-1)
// 结果
1
pow
语法:pow(a, b) 表示a的b次幂
pow(0cm, 0px)
pow(25, -2)
pow(25, 0.5)
pow(-25, 0.5)
pow(-25%, -0.5)
// 结果
1cm
0.0016
5
NaN
NaN%
mod
取余。语法:mod(a, b) 表示a % b的值
mod(0cm, 0px)
mod(11cm, 6px);
mod(-26%, -5);
// 结果
NaNcm;
5cm
-1%;
min
取最小值
min(5, 10)
min(3px, 42px, 1px, 16px)
// 结果
5
1px
max
取最大值
max(5, 10)
max(3%, 42%, 1%, 16%)
// 结果
10
42%
isnumber
去掉符号后,是否为number类型
isnumber(#ff0); // false
isnumber(blue); // false
isnumber("string"); // false
isnumber(1234); // true
isnumber(56px); // true
isnumber(7.8%); // true
isnumber(keyword); // false
isnumber(url(...)); // false
isstring
是否为字符串类型
isstring(#ff0); // false
isstring(blue); // false
isstring("string"); // true
isstring(1234); // false
isstring(56px); // false
isstring(7.8%); // false
isstring(keyword); // false
isstring(url(...)); // false
iscolor
是否为颜色值
iscolor(#ff0); // true
iscolor(blue); // true
iscolor("string"); // false
iscolor(1234); // false
iscolor(56px); // false
iscolor(7.8%); // false
iscolor(keyword); // false
iscolor(url(...)); // false
isunit
验证单位
isunit(11px, px); // true
isunit(2.2%, px); // false
isunit(33px, rem); // false
isunit(4rem, rem); // true
isunit(56px, "%"); // false
isunit(7.8%, '%'); // true
isunit(1234, em); // false
isunit(#ff0, pt); // false
isunit("mm", mm); // false
image-size
获取图片尺寸
包含两个宽高字段,image-width , image-height
image-size("file.png")
// 结果
10px 10px
data-uri
转化资源地址
data-uri('../data/image.jpg')
// 结果
url('data:image/jpeg;base64,bm90IGFjdHVhbGx5IGEganBlZyBmaWxlCg==')
// 在浏览器看到的结果为
url('../data/image.jpg')
还可以设置转化后的图片类型等参数
data-uri('image/jpeg;base64', '../data/image.jpg')
data-uri('image/svg+xml;charset=UTF-8', 'image.svg')
// 结果
url('data:image/jpeg;base64,bm90IGFjdHVhbGx5IGEganBlZyBmaWxlCg==')
url("data:image/svg+xml;charset=UTF-8,%3Csvg%3E%3Ccircle%20r%3D%229%22%2F%3E%3C%2Fsvg%3E")
|