Less——CSS 预处理器
为什么用Less
,原因之一就是CSS
太繁琐了,写起来没章法,没有变量,导致改动起来要修改好多地方;
同款预处理器还有:Sass || Stylus
;预处理器其实是把Less
这些代码编译成CSS
,看起来和TS / JS
的关系挺像的。
使用Less
由于Less
不能直接被浏览器引入使用,所以要介绍下怎么用;
-
编译成
CSS
后引入使用;- 手动编译:
npm i -g less
,全局安装Less
,使用命令lessc [option option=parameter ...] <source> [destination]
,直接将Less
文件编译成CSS
文件; - 编辑器的插件:
easy Less
等插件,保存时自动编译; - 项目中引入
Less && Less-loader
,在webpack
里配置
1 2 3 4
{ test: /\.less$/, loader: "style-loader!css-loader!less-loader", }
- 手动编译:
-
全局引入
less.js
,使得Less
文件在浏览器中变得可用;1 2
<link rel="stylesheet/less" type="text/css" href="styles.less" /> <script src="less.js" type="text/javascript"></script>
语法详解
变量
// less
@val: white;
@selector: #id;
@prop: color;
@url: '../img';
@backImg: background-image;
@mixin: {
margin-left: 10px;
font-size: 16px;
};
@num: 200px;
@numb: @num - 100;
@{selector} {
@{prop}: @val;
@{backImg}: url('@{url}/index.jpg');
@mixin ();
width: @num - 10;
height: @numb * 2;
}
// css
#id {
color: white;
background-image: url('../img/index.jpg');
margin-left: 10px;
font-size: 16px;
width: 190px;
height: 200px;
}
变量作用域问题:就近原则,并且使用变量可以在变量定义之前;
你甚至可以用变量来定义另一个变量;
@var2: red;
@var: 'var2';
div {
color: @@var;
}
/* 生成的 CSS */
div {
color: red;
}
嵌套
在嵌套中,&
代表了上一层的选择器;
// 编译前
@{selector} {
&::after {
content: '?';
}
p {
text-decoration: double;
}
&-container {
color: red;
&__content {
background-color: blue;
}
}
}
// 编译后
#id::after {
content: '?';
}
#id-container {
color: red;
}
#id-container__content {
background-color: blue;
}
#id p {
text-decoration: double;
}
媒体查询
// less
@{selector} {
@media screen {
@media (max-width: 768px) {
@mixin ();
}
}
@media tv {
@{prop}: red;
}
}
// css
@media screen and (max-width: 768px) {
#id {
margin-left: 10px;
font-size: 16px;
}
}
@media tv {
#id {
color: red;
}
}
混入
其实刚刚已经用了,混入用的函数可传参数,并且和 ES6 一样可以有默认参数,@arguments
则表示所有参数,需要注意的是传入的参数需要带有单位;混入还有个要注意的点,在定义混入时,如果不加()
,会在CSS
里面渲染出混入的选择器和样式,如果加了()
,就不会渲染;
.container {
color: red;
}
#container {
.container();
// 或者
.container;
}
// 传参
.container(@color: red, @param1: 10px) {
color: @color;
width: @param1;
border: @arguments;
}
@{selector} {
.container();
}
.div {
.container(blue, 20px);
}
// css
#id {
color: red;
width: 10px;
border: red 10px;
}
.div {
color: blue;
width: 20px;
border: blue 20px;
}
// less
.mixin() {
color: red;
}
@{selector} {
.mixin();
}
// css
#id {
color: red;
}
混入的方法也可以用编译时多态来定义;
.func(top,@param1) {
top: @param1;
}
.func(bottom, @param1) {
bottom: @param1;
}
.func(@_,@param1) {
left: 0;
right: 0;
}
@{selector} {
.func(top, 10px);
}
// css
#id {
top: 10px;
left: 0;
right: 0;
}
这种模式会匹配第一个参数,找到匹配度最高的那个函数,如果匹配度相同就全部选择,并且样式会覆盖;如果匹配的参数是个变量,会直接匹配。
上面这个函数可以看到,匹配了第一个参数是top && @_
的两个函数,都混入了选择器中。
混入方法的命名空间
.fun1() {
.fun2(@para2: 20px) {
width: @para2;
height: @para2;
&:hover {
background-color: white;
}
}
}
@{selector} {
.fun1 > .fun2(10px);
}
// css
#id {
width: 10px;
height: 10px;
}
#id:hover {
background-color: white;
}
这是中文文档的一个例子,可以用选择器>
或者直接.fun1.fun2
调用,这其实是直接后代选择器,且父选择器不能加括号;而且命名空间函数必须要先引入命名空间,才可以调用里面的函数;另外还可以看到,内部方法可以使用外部方法的参数。
方法的条件筛选
Less
没有if else
语法,但是有when
语法;
.fun3 {
.fun1(@para1, @para2) when (@para1 > 10px) and (@para2 =#eee) {
width: @para1;
color: @para2;
}
.fun2(@para1, @para2: 1px) when not (@para1 > 10px) {
width: @para1;
}
.fun3(@para1, @para2) when (@para1 > 10px),
(@para2 > 20px) {
width: @para1 + @para2;
}
}
@{selector} {
.fun3 > .fun3(20px, 10px);
.div {
.fun3 > .fun1(20px, #eee);
}
.text {
.fun3 > .fun2(5px);
}
}
// css
#id {
width: 30px;
}
#id .div {
width: 20px;
color: #eee;
}
#id .text {
width: 5px;
}
数量不定的参数
Less
还可以使用扩展运算符
.fun4(...) {
border: @arguments;
}
@{selector} {
.fun4(1px, solid, red);
}
// css
#id {
border: 1px solid red;
}
需要使用
!important
时,直接在方法后面加上!important
即可;
循环方法
Less
虽然没有提供for
语法,但是可以借用递归来实现;
.for-fun(@n, @i: 1) when (@i =< @n) {
&:nth-of-type(@{i}) {
animation-delay: (0.2s * @i);
}
.for-fun(@n, (@i + 1));
}
li {
animation: move 1s ease infinite;
.for-fun(5);
}
// css
li {
animation: move 1s ease infinite;
}
li:nth-of-type(1) {
animation-delay: 0.2s;
}
li:nth-of-type(2) {
animation-delay: 0.4s;
}
li:nth-of-type(3) {
animation-delay: 0.6s;
}
li:nth-of-type(4) {
animation-delay: 0.8s;
}
li:nth-of-type(5) {
animation-delay: 1s;
}
属性拼接
+_: space; +: comma
/* Less */
.boxShadow() {
box-shadow+: inset 0 0 10px #555;
}
.main {
.boxShadow();
box-shadow+: 0 0 20px black;
}
/* 生成后的 CSS */
.main {
box-shadow: inset 0 0 10px #555, 0 0 20px black;
}
/* Less */
.Animation() {
transform+_: scale(2);
}
.main {
.Animation();
transform+_: rotate(15deg);
}
/* 生成的 CSS */
.main {
transform: scale(2) rotate(15deg);
}
方法返回值的实例
.fun5(@p1, @p2) {
@return: (@p1 + @p2);
}
.div {
.fun5(10px, 20px);
width: @return;
}
// css
.div {
width: 30px;
}
需要注意的点是返回值需要用()
包裹,并且+
和变量名之间需要有空格,否则会被识别为字符串;
继承
extend
语法,是作为Less
中的一个伪类存在的;和混入方法的区别就是,继承在编译时会把被继承的属性写在一起,减少代码冗余,而混入方法会分开,看个例子吧;
/* extend */
#main {
width: 200px;
}
#main {
&:after {
content: 'Less is good!';
}
}
#wrap:extend(#main aLess) {
}
/* css */
#main,
#wrap {
width: 200px;
}
#main:after,
#wrap:after {
content: 'Less is good!';
}
/* mixin */
.mix {
width: 100px;
&::before {
content: '123123';
}
}
#mixin {
.mix;
}
/* css */
.mix {
width: 100px;
}
.mix::before {
content: '123123';
}
#mixin {
width: 100px;
}
#mixin::before {
content: '123123';
}
还是比较明显的区别,用继承语法会把相同属性的几个选择器写在一起,而混入语法就不会;
另外还要提的一个点就是aLess
这个关键字,不用aLess
的话就只会继承main
,而不会继承:after
部分;
/* not aLess */
.extend {
height: 100px;
.inner {
height: 20px;
}
}
.div:extend(.extend) {
width: 100px;
}
/* css */
.extend,
.div {
height: 100px;
}
.extend .inner {
height: 20px;
}
.div {
width: 100px;
}
/* aLess */
.extend {
height: 100px;
.inner {
height: 20px;
}
}
.div2:extend(.extend aLess) {
width: 200px;
}
/* css */
.extend,
.div2 {
height: 100px;
}
.extend .inner,
.div2 .inner {
height: 20px;
}
.div2 {
width: 200px;
}
区别还是比较明显的,就是有没有继承.inner
这个选择器的区别了。
其他注意点
- 可以选择多个继承的选择器,写法也有两种,一种是
div:extend(.extend):extend(.another)
,还有一种是div:extend(.extend, another)
- 也可以只选择某个选择器的子选择器,像上面那个例子就可以选择
.div:extend(.extend .inner)
- 继承语法需要放在选择器最后,不能在继承语法后面再写选择器。
导入
import
语法,@import (options) "filename"
- 和
CSS
的区别就是无所谓在哪引入,类似JS
的变量提升,而在CSS
里需要在使用前引入; - 还可以省略后缀,大部分情况都会把文件当做是
Less
文件处理,除非特别设置了一些options
;
options
共有以下几种,可以组合使用的;
reference
: 单纯引入,不会编译到最终输出的CSS
文件里;inline
: 会包含在最终的输出文件里,但不会编译处理;less
: 无论文件后缀名是什么,都会当成Less
文件处理;css
: 当做CSS
文件处理;once
: 默认行为,文件只会被导入一次,即使写了两次导入语句,第二句会被忽略;multiple
: 允许多次导入,会多次编译;optional
: 即使当导入的文件没有找到,也会执行编译;
函数
其实前面也提到过我们可以单独引入less.js
来在浏览器环境下直接用Less
语法,所以其实我们在Less
中可以用一些JS
的函数;
丢,函数太多了,看文档
杂项
Less
中有两种注释,单行和多行,其实在CSS
里面只能识别多行,所以单行不会被编译在CSS
文件里;- 有时候需要取消编译某一个属性,可以这样写
prop: ~'calc(300px - 30px)'
,注意使用~
并且把不需要编译的值用''
包裹; - 还可以在
Less
文件里写JS
,目前搜到的方法是要引入less.js
,但是目前尝试下来是不行的; - 另外有一点要注意,使用
Less.js
引入时,如果使用静态文件直接访问html
文件,会提示跨域错误,所以要起本地服务器的方式,IIS node
都可以。