前端构建 Less入门(CSS预处理器) - 好资源导航网
前端构建 Less入门(CSS预处理器)
Less是一门CSS预处理语言,它扩充了CSS语言,增加了诸如变量、混合(mixin)、函数等功能,让CSS更易维护、方便制作主题、扩充。
Less可以运行在Node、浏览器和Rhino平台上。网上有很多第三方工具帮助你编译Less源码。
一、前言
说到前端构建怎能缺少CSS预处理器呢!其实CSS的预处理器有很多啦,比较出名的有Scss、Sass、Stylus和Less。(最近还听说出现了Autoprefixer等CSS后处理器,可参考@一丝的PPT)
众多CSS预处理器中Less的语法最接近原生CSS,因此相对来说更容易上手,假如有JS、C#等编程经验的话,其实上述的几种预处理器的学习成本也不会特别高。下面是我们这阵子的学习笔记,以便日后查阅。
最好的入门教程——官网地址:http://lesscss.org/
最佳实践之一——Bootstrap
由于内容较多,特设目录一坨:
二、搭建学习环境
三、内联样式和外联样式
四、语法
1.注释
2.变量(Variable)
列表类型
3.嵌套(Nested)
4.父选择器引用(ParentSelector)
5.导入指令(Import)
6.继承(Extend)
7.混合(Mixin)
8.选择、循环作业控制
五、运算符
六、函数
七、通过Lessc将Less引入开发环境
八、实战一下
九、与Grunt结合
十、总结
二、搭建学习环境
搭建Less的学习环境非常简单,只需在
标签前通过引入处理器即可实现浏览器端中将less预编译为css样式。更有效的方式是通过如下代码监测less样式,自动编译为css样式,从而减少我们修改less代码后需按F5后才看到实际效果的繁琐步骤。
三、内联样式和外联样式
基于我们现在使用的是浏览器端进行预编译,因此Less可用于内联样式和外联样式当中。
内联样式如下:
//less代码
外联样式引入如下:
四、语法
1.注释
//单行注释,不会作为最终输出
/*
多行注释,以原生CSS的/*注释....*/形式作为最终输出
*/
2.变量(Variable)
Less中的变量有以下规则:
- 以@作为变量的起始标识,变量名由字母、数字、_和-组成
- 没有先定义后使用的规定;
- 以最后定义的值为最终值;
- 可用于rule值、rule属性、rule属性部件、选择器、选择器部件、字符串拼接;
- 定义时"@变量名:变量值;"的形式;引用时采用"@变量名"或"@{变量名}"的形式;
- 存在作用域,局部作用域优先级高于全局作用域。
Less源码:
@color:color;
@dialog:.dialog;
@suffix:fix;
//空格将被忽略,若要保留空格则需要使用单引号或双引号
@hi:'hello';
@dear:there;
.dialog{
//用于rule属性部件,必须使用"@{变量名}"的形式
background-@{color}:#888;
//用于rule属性,必须使用"@{变量名}"的形式
@{color}:blue;
}
//用于选择器,必须使用"@{变量名}"的形式
@{dialog}{
width:200px;
}
@{dialog}::after{
content:':@{hi}@{dear}!';//用于字符串拼接,必须使用"@{变量名}"的形式
}
@h:1000px;
//用于选择器部件,必须使用"@{变量名}"的形式
.ie-@{suffix}{
@h:30px;//存在作用域,局部作用域优先级高于全局作用域。
height:@h;//用于属性值,两种形式均可使用
line-height:30px;
}
//1.以@作为变量的起始标识,变量名由字母、数字、_和-组成
//2.没有先定义后使用的规定;
@dialog-border-color:#666;
@dialog-border-width:10px;
@dialog-border-width:1px;//3.以最后定义的值为最终值;
最终输出:
.dialog{
background-color:#888;
color:blue;
}
.dialog{
width:200px;
}
.dialog::after{
content:':hellothere!';
}
.ie-fix{
height:30px;
line-height:30px;
}
列表类型
less变量除了支持#FFF,12px,12,test等单值类型外,还支持列表类型,通过内置函数extract通过索引获取列表元素,通过内置函数length获取列表的元素个数
@colors:#FFF,#0F0,#F0F;
.skin{
color:extract(@colors,0);
height:12px*length(@colors);
}
最终输出:
.skin{
color:#FFF;
height:36px;
}
3.嵌套(Nested)
Less源码:
.main{
padding:10px;
>div{
width:100px;
}
.aside{
width:200px;
}
}
最终输出:
.main{
padding:10px;
}
.main>div{
width:100px;
}
.main.aside{
width:200px;
}
4.父选择器引用(ParentSelector)
- 采用&引用完整的父选择器
- 可通过追加和预追加的方式加工&,从而生成新的选择器
- 通过&::after等方式添加伪元素、伪类样式规则集合
- 同一个选择器可使用多个&
- 通过在选择器后添加"空格&"的方式,可将当前选择器排列到最前面
- &指向组选择器时,会生成新的组选择器
Less源码:
/*
*采用&引用完整的父选择器
*可通过追加和预追加的方式加工&,从而生成新的选择器
*通过&::after等方式添加伪元素样式规则集合
*同一个选择器可使用多个&
*通过在选择器后添加"空格&"的方式,可将当前选择器排列到最前面
*/
@bg:#aaa;
#ps1.btn{
background-color:@bg;
border-radius:5px;
&:hover{
background-color:lighten(@bg,30%);
cursor:pointer;
}
&-msg,&-eof{
color:blue;
}
.no-borderradius&{
background-image:url('img/btn-bg.png');
}
}
/*
*&指向组选择器时,会生成新的组选择器
*/
#dummy1,.dummy1{
&:hover{
color:red;
}
&+&{
font-size:12px;
}
}
最终输出:
/*
*采用&引用完整的父选择器
*可通过追加和预追加的方式加工&,从而生成新的选择器
*通过&::after等方式添加伪元素样式规则集合
*同一个选择器可使用多个&
*通过在选择器后添加"空格&"的方式,可将当前选择器排列到最前面
*/
#ps1.btn{
background-color:#aaaaaa;
border-radius:5px;
}
#ps1.btn:hover{
background-color:#f6f6f6;
cursor:pointer;
}
#ps1.btn-msg,
#ps1.btn-eof{
color:blue;
}
.no-borderradius#ps1.btn{
background-image:url('img/btn-bg.png');
}
/*
*&指向组选择器时,会生成新的组选择器
*/
#dummy1:hover,
.dummy1:hover{
color:red;
}
#dummy1+#dummy1,
#dummy1+.dummy1,
.dummy1+#dummy1,
.dummy1+.dummy1{
font-size:12px;
}
5.导入指令(Import)
less样式文件可通过@import'文件路径';引入外部的less文件。
注意:
不带扩展名或带非.less的扩展名均被视为less文件;
@import可出现在任何位置,而不像css的@import那样只能放在文件第一行。
另外@import还提供了6个可选配置项(分别为reference,inline,less,css,once,multiple),用来改变引入文件的特性。语法为:@import(reference)'文件路径';。下面为各配置项的具体说明:
1.@import(reference)"文件路径";
将引入的文件作为样式库使用,因此文件中样式不会被直接编译为css样式规则。当前样式文件通过extend和mixins的方式引用样式库的内容。
2.@import(inline)"文件路径";
用于引入与less不兼容的css文件,通过inline配置告知编译器不对引入的文件进行编译处理,直接输出到最终输出。注意:引入的文件和当前文件会被编译为一个样式样式
3.@import(less)"文件路径";
默认使用该配置项,表示引入的文件为less文件。
4.@import(css)"文件路径";
表示当前操作为CSS中的@import操作。当前文件会输出一个样式文件,而被引入的文件自身为一个独立的样式文件
5.@import(once)"文件路径";
默认使用该配置项,表示对同一个资源仅引入一次。
6.@import(multiple)"文件路径";
表示对同一资源可引入多次。
6.继承(Extend)
有两种语法形式,:extend(){}和{&:extend();}
Less源码:
.animal{
color:#fff;
}
/*语法1::extend(){}*/
.bear:extend(.animal){
width:100px;
height:100px;
}
/*语法2:{&:extend();}*/
.deer{
&:extend(.animal);
width:50px;
height:50px;
}
最终输出:
.animal,
.bear,
.deer{
color:#fff;
}
/*语法1::extend(){}*/
.bear{
width:100px;
height:100px;
}
/*语法2:{&:extend();}*/
.deer{
width:50px;
height:50px;
}
注意事项:
6.1.父选择器必须严格匹配,除了属性选择器中属性值引号不必匹配外,或添加all关键字外。
Less源码:
*.parent{
height:100px;
.hair{
color:#f27;
}
[name=eyes]{
color:#768;
}
}
//匹配失败
.son:extend(.parent){}
.son:extend(.hair){}
//匹配成功
.son:extend(*.parent[name='eyes']){}
.son:extend(*.parent[name="eyes"]){}
//all关键字会匹配所有包含parentSelector内容的选择器,并以selector替换parentSelector来生成新的选择器
//下面的内容会生成*.son,*.son.hair,*.son[name=eyes]三个新的选择器
.son:extend(.parentall){}
最终输出:
*.parent,
*.son{
height:100px;
}
*.parent.hair,
*.son.hair{
color:#f27;
}
*.parent[name=eyes],
.son,
.son,
*.son[name=eyes]{
color:#768;
}
6.2.父选择器不支持变量形式
Less源码:
@p1:.parent1;
@p2:.parent2;
.parent1{
height:100px;
}
@{p2}{
height:200px;
}
//匹配失败
//形式1,不支持以变量作入参
.son1:extend(@{p1}){}
//形式2,不支持以变量作为选择器的规则集合
.son1:extend(.parent2){}
//匹配成功
.son2:extend(.parent1){}
@s3:son3;
.@{s3}:extend(.parent1){}
最终输出:
.parent1,
.son2,
.son3{
height:100px;
}
.parent2{
height:200px;
}
6.3.mediaquery影响继承的作用域
6.3.1.mediaquery内的extend操作,仅能继承当前块的其他选择器样式。
注意:不能extend当前mediaquery块内部的子mediaquery块中的选择器样式;但可以extend父mediaquery块的选择器样式。
Less源码:
.parent1{
height:200px;
}
@mediascreen{
.parent1{
height:100px;
}
//无法继承子mediaquery块的选择器样式
.son1:extend(.parent2){}
@media(min-width:1023px){
//继承父mediaquery块的选择器样式
.son2:extend(.parent1){}
.parent2{
width:200px;
}
}
}
最终输出:
.parent1{
height:200px;
}
@mediascreen{
.parent1{
height:100px;
}
}
@mediascreenand(min-width:1023px){
.parent2{
width:200px;
}
}
6.3.2.非mediaquery内的extend操作,将会继承所有mediaquery中匹配的选择器样式。
Less源码:
@mediascreen{
.parent{
height:100px;
}
@media(min-width:1023px){
.parent{
width:200px;
}
}
}
.son:extend(.parent){}
最终输出:
@mediascreen{
.parent,
.son{
height:100px;
}
}
@mediascreenand(min-width:1023px){
.parent,
.son{
width:200px;
}
}
6.4.增强的mixin定义mixin时仅能使用类选择器和ID选择器,而extend操作可对应所有的选择器,因此当没有动态入参而又需要类选择器和ID选择器以外的选择器时,可使用extend来实现mixin的功能。
7.混合(Mixin)
Mixin相当于macro,会将样式规则内联到调用的位置中。而Less中的mixin有以下的注意点:
7.1.类选择器、ID选择器自动被定义为mixin,而且具有命名空间;
Less源码:
.animal{
.human{
#fsjohnhuang{
.hair{
color:#000;
}
}
}
}
.front-end-monkey{
//或者.animal.human#fsjohnhuang.hair();
//或者.animal>.human>#fsjohnhuang>.hair;
//或者.animal>.human>#fsjohnhuang>.hair();
//即可调用mixin
.animal.human#fsjohnhuang.hair;
}
最终输出:
.animal.human#fsjohnhuang.hair{
color:#000;
}
.front-end-monkey{
color:#000;
}
7.2.显示定义不带参数和带参数的样式库(mixin库),不会输出到最终输出中,仅供调用;
Less源码:
//定义不带参数的mixin
.animal(){
color:#000;
}
//定义带参数的mixin
//注意:由于,和;均可用于作为参数分隔符,但由于如background、border等样式属性支持属性值组,而,则作为属性值组元素分隔符,因此推荐使用;作为参数分隔符
.dog(@type;@age){
height:@type*@age*12px;
}
//定义带参数默认值的mixin
.cat(@type;@age:1){
height:@type*@age*5px;
}
//调用才会出现在最终输出
.chihuahua{
.dog(1;2);
}
最终输出:
.chihuahua{
height:24px;
}
7.3.mixin内置两个特殊的对象@arguments和@reset。@arguments代表mixin的所有入参,而@reset代表mixin的...入参数组。
Less源码:
.dog(@type;@age;@rest...){
height:@type*@age*12px;
border:@rest;
}
.cat(@solid;@w;@color){
border:@arguments;
}
.chihuahua{
.dog(1;2;solid;1px;red);
}
.mimi{
.cat(solid;2px;blue);
}
最终输出:
.chihuahua{
height:24px;
border:solid1pxred;
}
.mimi{
border:solid2pxblue;
}
7.4.mixin的重载可定义多个同名mixin,调用时只要参数数量匹配则会执行相应的mixin。
Less源码:
.dog(@name){
&::after{
content:@name;
}
}
.dog(@name;@age){
height:@age*4px;
}
.dog(@name;@age;@width:20px){
height:@age*12px;
width:@width;
}
//仅匹配到.dog(@name){
.one-dog{
.dog('chihuahua');
}
//匹配到.dog(@name;@age)和.dog(@name;@age;@width:20px)
.two-three-dog{
.dog('two-three-dog',2);
}
//参数的模式匹配
//当第一参数值为mimi时调用该mixin
.cat(mimi,@age){
height:@age*22px;
}
//当第一参数值为mini时调用该mixin
.cat(mini,@age){
height:@age*12px;
}
//不管第一参数值为啥均调用该mixin
.cat(@any,@age){
color:#f3c;
}
.mycat{
.cat(mini,1);
}
最终输出:
.one-dog::after{
content:'chihuahua';
}
.two-three-dog{
height:8px;
height:24px;
width:20px;
}
.mycat{
height:12px;
color:#f3c;
}
8.选择、循环作业控制
Less中通过混合(Mixin)后的when关键字来提供选择的作业控制,通过递归来实现循环的作业控制。
Less源码:
//条件匹配
//true值匹配,仅实参为true时才匹配成功
.truth(@a)when(@a){
&::after{
content:@a;
}
}
//匹配成功
.truth1{
.truth(true);
}
//匹配失败
.truth2{
.truth(#fff);
}
/*类型判断函数
*iscolor
*isnumber
*isstring
*iskeyword
*isurl
*/
.bear(@color)when(iscolor(@color)){
color:@color;
}
/*单位判断函数
*ispixel
*ispercentage
*isem
*isunit
*/
.bear(@height)when(ispixel(@height)){
height:@height;
}
//=,>,>=,<=,<关系运算符
.rich(@h)when(@h>1000){
height:@h;
}
//and、not、or(使用,号表示)逻辑运算符
.huge(@h,@w)when(@h>180)and(@w>180){
height:@h;
width:@w;
}
//使用&when()实现if语句
@debug:true;
&when(@debug){
div{
border:solid1pxred;
}
}
//通过递归实现循环
.generate-columns(4);
.generate-columns(@n,@i:1)when(@i=<@n){
.column-@{i}{
width:(@i*100%/@n);
}
.generate-columns(@n,(@i+1));
}
最终输出:
.truth1::after{
content:true;
}
/*类型判断函数
*iscolor
*isnumber
*isstring
*iskeyword
*isurl
*/
/*单位判断函数
*ispixel
*ispercentage
*isem
*isunit
*/
div{
border:solid1pxred;
}
.column-1{
width:25%;
}
.column-2{
width:50%;
}
.column-3{
width:75%;
}
.column-4{
width:100%;
}
五、运算符
Less还支持+、-、*、/运算符。但对单位不一致的运算数进行运算要注意以下两点:
1.运算数与运算符间必须用空格分隔;
2.以第一个运算数的单位作为运算结果的单位;
Less源码:
//运算数与运算符间没有空格
@fail:1px+2em;
.fail{
height:@fail;
}
@success1:1px+2em;
.success1{
height:@success1;
}
@success2:2px+1em;
.success2{
height:@success2;
}
最终输出:
.fail{
height:1px2em;
}
.success1{
height:3px;
}
.success2{
height:3em;
}
六、函数
Less为我们提供了一个功能强大的内置函数库,其中绝大部分为颜色处理函数。下面着重介绍MiscFunction中的default函数、StringFunction中的escape函数和颜色处理函数。
1.default函数
示例:
//forteenager
.person(@age)when(@age<=19)and(@age>=13){
height:@age*10px;
}
//forchild
.person(@age)when(@age<13){
height:@age*6px;
}
//foradult
.person(@age)when(default()){
height:180px;
}
.son{
.person(10);
}
.daughter{
person(17);
}
.father{
.person(27);
}
最终输出:
.son{
height:60px;
}
.daughter{
height:170px;
}
.father{
height:180px;
}
虽然上述示例逻辑上不合理。但可以看出default函数用于条件控制当中,充当else或switch语句中default的角色。
通过官网提供的综合示例我们可以更好理解它的用法:
//Less源码
.x{
.m(red){case-1:darkred}
.m(blue){case-2:darkblue}
.m(@x)when(iscolor(@x))and(default()){default-color:@x}
.m('foo'){case-1:Iam'foo'}
.m('bar'){case-2:Iam'bar'}
.m(@x)when(isstring(@x))and(default()){default-string:andIamthedefault}
&-blue{.m(blue)}
&-green{.m(green)}
&-foo{.m('foo')}
&-baz{.m('baz')}
}
//最终输出
.x-blue{
case-2:#00008b;
}
.x-green{
default-color:#008000;
}
.x-foo{
case-1:Iam'foo';
}
.x-baz{
default-string:andIamthedefault;
}
注意:
1.default函数必须在条件控制语句当中使用;
2.default函数可实现比else更复杂的功能,如下:
//Less源码
.mixin(@value)when(ispixel(@value)){width:@value}
.mixin(@value)whennot(default()){padding:(@value/5)}
div-1{
.mixin(100px);
}
div-2{
/*...*/
.mixin(100%);
}
//最终输出:
div-1{
width:100px;
padding:20px;
}
div-2{
/*...*/
}
2.escape函数
顾名思义就是对字符串中的特定字符进行编码,该函数将对\,#,^,(,),{,},|,:,>,<,;,],[和=字符进行编码。
3.颜色处理函数
颜色处理函数又分为四大类:颜色定义函数(ColorDefinition)、颜色通道值获取函数(ColorChannel)、颜色通道值修改函数(ColorOperationFunction)、混色函数(ColorBlending)。
这里仅仅介绍常用的lighten和darken函数。
lighten(color,amount),color为颜色,amount为增加的亮度值,取值范围为0-100%。
darken(color,amount),color为颜色,amount为减少的亮度值,取值范围为0-100%。
七、通过Lessc将Less引入开发环境
到这里我想大家已经对Less有一定程度的了解,并希望在将其加入你的开发工具包中。但通过less.js将Less解析器引入到浏览器肯定是不适合开发的,而cli工具lessc更适合开发环境中使用。在使用之前我们先要通过npm来安装less。
npminstall-gless
然后我们就可以通过lessc[optionoption=parameter...]
lessc的option选项较多,我将主要的选项分为lessc命令信息相关、sourcemap相关、@import指令相关和插件相关四类。
1.lessc命令信息相关
lessc-h,获取lessc命令的帮助信息;
lessc-v,获取lessc命令的版本号。
2.sourcemap相关
由于在浏览器直接查看和操作的是CSS样式规则,而我们开发时使用的Less代码,这会导致难以找到CSS样式规则所对应的Less代码从而增大调试难度。而sourcemap就是为了解决这一痛点而提出的技术解决方案,其原理就是通过一个map文件来保存两个文件中代码的对应关系,然后支持sourcemap的浏览器的devTools中就会根据这些对应关系来定位相应的Less代码。(Chrome和FF均支持sourcemap,IE11及以下均不支持)
若对sourcemap不太了解的可以参考《前端构建:SourceMaps详解》
--source-map,生成与生成的css同名的sourcemap文件(例如生成的css文件为main.css,那么sourcemap文件就是main.css.map),且与css文件位于同一目录下;
--source-map=,自定义sourcemap文件的路径;
--source-map-rootpath=,假如main.less文件位于src/less下,而生成的css和sourcemap文件位于bin/style下,那么就需要修改sourcemap文件中用于指向less文件路径的sources属性值,浏览器才能通过sourcemap文件查找到less文件。上述例子的命令为:
lessc--source-map--source-map-rootpath=../../src/less/main.lesssrc/less/main.lessbin/style/main.css
--source-map-map-inline,以dataURIScheme的形式将sourcemap文件内容内嵌到css文件中。
--source-map-url=,默认情况下css文件的最后一行会插入如/*#sourceMappingURL=main.css.map*/的内容来指向sourcemap文件,而该选项则可修改sourceMappingURL的值。
3.@import指令相关
--include-path=[;]*,通过@import指令引入外部less或css等文件时存在引入的文件路径到底是以哪个目录作为参考的问题,我们可以通过该选项来指定参考目录,当存在多个参考目录时,使用;号分隔。
--relative-urls或-ru,用于保持样式库中的图片等资源的相对路径。示例:
#main.less
@import"files/backgrounds.less";
#files/backgrounds.less
.icon-1{
background-image:url('images/lamp-post.png');
}
不使用该选项时:
.icon-1{
background-image:url('images/lamp-post.png');
}
使用该选项时:
.icon-1{
background-image:url('files/images/lamp-post.png');
}
4.插件相关
lessc以插件的形式来增强其功能,下面仅介绍clean-css插件,其他插件请参考http://lesscss.org/usage/#plugins-list-of-less-plugins
clean-css插件用于压缩css文件(less-plugin-clean-css@github)
首先通过npm安装插件npminstall-gless-plugin-clean-css,然后通过--clean-css选项来启动CSS压缩功能。
如:lesscfile.less--clean-css="--s1--advanced--compatibility=ie8"
八、实战一下
先假定我们开发环境的目录结构如下(灰色表示文件由构建工具生成):
sample
|--build.bat 构建工具
|--lib 第三方依赖库
| |--less
| |--base.less
| |--img
| |--nav.png
|--src 源码
| |--less
| | |--main.less
| |--index.html
|--bin 编译后的文件
| |--style
| |--main.css
| |--main.css.map
| |--index.html
|--dist 发布文件
|--lib
||--less
| |--img
| |--nav.png
|--app
|--style
| |--main.css
|--index.html
index.html文件内容: