一、前言                             

说到前端构建怎能缺少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)

   6.1. 父选择器必须严格匹配,除了属性选择器中属性值引号不必匹配外,或添加all关键字外。

   6.2. 父选择器不支持变量形式

  6.3. media query影响继承的作用域

    6.3.1. media query内的extend操作,仅能继承当前块的其他选择器样式。

    6.3.2. 非media query内的extend操作,将会继承所有media query中匹配的选择器样式。

   6.4. 增强的mixin定义mixin时仅能使用类选择器和ID选择器,而extend操作可对应所有的选择器,因此当没有动态入参而又需要类选择器和ID选择器以外的选择器时,可使用extend来实现mixin的功能。

7. 混合(Mixin)

  7.1. 类选择器、ID选择器自动被定义为mixin,而且具有命名空间;

  7.2. 显示定义不带参数和带参数的样式库(mixin库),不会输出到最终输出中,仅供调用;

  7.3. mixin的中内置两个特殊的对象@arguments和@reset。@argumentsk代表mixin的所有入参,而@reset代表mixin的...入参数组。

  7.4. mixin的重载可定义多个同名mixin,调用时只要参数数量匹配则会执行相应的mixin。

8. 选择、循环作业控制

五、运算符

六、函数

   1. default函数

2. escape函数

3. 颜色处理函数

七、通过Lessc将Less引入开发环境

八、实战一下

九、与Grunt结合

十、总结

二、搭建学习环境                          

搭建Less的学习环境非常简单,只需在</body>标签前通过<script type="text/javascript" src="less.js"></script>引入处理器即可实现浏览器端中将less预编译为css样式。更有效的方式是通过如下代码监测less样式,自动编译为css样式,从而减少我们修改less代码后需按F5后才看到实际效果的繁琐步骤。

<script>less = { env: 'development'};</script>
<script src="less.js"></script>
<script>less.watch();</script>

三、内联样式和外联样式                      

基于我们现在使用的是浏览器端进行预编译,因此Less可用于内联样式和外联样式当中。

内联样式如下:

<style type="text/less">// less 代码
</style>

外联样式引入如下:

<link rel="stylesheet/less" type="text/css" href="文件.less"/>

四、语法                              

  1. 注释

// 单行注释,不会作为最终输出
/* 多行注释,以原生CSS的/*注释....*/形式作为最终输出*/

  2. 变量(Variable)

Less中的变量有以下规则:

  1. 以@作为变量的起始标识,变量名由字母、数字、_和-组成
  2. 没有先定义后使用的规定;
  3. 以最后定义的值为最终值;
  4. 可用于rule值、rule属性、rule属性部件、选择器、选择器部件、字符串拼接;
  5. 定义时 "@变量名: 变量值;" 的形式;引用时采用 "@变量名" 或 "@{变量名}" 的形式;
  6. 存在作用域,局部作用域优先级高于全局作用域。

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: ': hello there!';
}
.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)

  1. 采用&引用完整的父选择器
  2. 可通过追加和预追加的方式加工&,从而生成新的选择器
  3. 通过&::after等方式添加伪元素、伪类样式规则集合
  4. 同一个选择器可使用多个&
  5. 通过在选择器后添加 "空格&"的方式,可将当前选择器排列到最前面
  6. &指向组选择器时,会生成新的组选择器

  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文件。

  注意:

  1. 不带扩展名或带非.less的扩展名均被视为less文件;
  2. @import可出现在任何位置,而不像css的@import那样只能放在文件第一行。

另外@import还提供了6个可选配置项(分别为reference,inline,less,css,once,multiple),用来改变引入文件的特性。语法为:  @import (reference) '文件路径'; 。下面为各配置项的具体说明:

1. @import (reference) "文件路径"; 
将引入的文件作为样式库使用,因此文件中样式不会被直接编译为css样式规则。当前样式文件通过extendmixins的方式引用样式库的内容。
2. @import (inline) "文件路径"; 
用于引入与less不兼容的css文件,通过inline配置告知编译器不对引入的文件进行编译处理,直接输出到最终输出。注意:引入的文件和当前文件会被编译为一个样式样式
3. @import (less) "文件路径"; 
默认使用该配置项,表示引入的文件为less文件。
4. @import (css) "文件路径"; 
表示当前操作为CSS中的@import操作。当前文件会输出一个样式文件,而被引入的文件自身为一个独立的样式文件
5. @import (once) "文件路径"; 
默认使用该配置项,表示对同一个资源仅引入一次。
6. @import (multiple) "文件路径"; 
表示对同一资源可引入多次。

  6. 继承(Extend)

有两种语法形式, <selector>:extend(<parentSelector>){} 和 <selector>{ &:extend(<parentSelector>); }

Less源码:

.animal{color: #fff;
}
/* 语法1:<selector>:extend(<parentSelector>){} */
.bear:extend(.animal){width: 100px;height: 100px;
}
/* 语法2:<selector>{ &:extend(<parentSelector>); } */
.deer{&:extend(.animal);width: 50px;height: 50px;
}

最终输出:

.animal,
.bear,
.deer {color: #fff;
}
/* 语法1:<selector>:extend(<parentSelector>){} */
.bear {width: 100px;height: 100px;
}
/* 语法2:<selector>{ &:extend(<parentSelector>); } */
.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(.parent all){}

最终输出:

*.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. media query影响继承的作用域

  6.3.1. media query内的extend操作,仅能继承当前块的其他选择器样式。

      注意:不能extend当前media query块内部的子media query块中的选择器样式;但可以extend父media query块的选择器样式。

   Less源码:

.parent1{height: 200px;
}
@media screen{.parent1{height: 100px;}    // 无法继承子media query块的选择器样式
   .son1:extend(.parent2){}@media (min-width: 1023px){// 继承父media query块的选择器样式
      .son2:extend(.parent1){}.parent2{width: 200px;}}
}   

  最终输出:

.parent1 {height: 200px;
}
@media screen {.parent1 {height: 100px;}
}
@media screen and (min-width: 1023px) {.parent2 {width: 200px;}
}

  6.3.2. 非media query内的extend操作,将会继承所有media query中匹配的选择器样式。

  Less源码:

@media screen{.parent{height: 100px;}@media (min-width: 1023px){.parent{width: 200px;}}
}
.son:extend(.parent){}

  最终输出:

@media screen {.parent,.son {height: 100px;}
}
@media screen and (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: solid 1px red;
}
.mimi {border: solid 2px blue;
}

  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: solid 1px red;}
}// 通过递归实现循环
.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: solid 1px red;
}
.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: 1px 2em;
}.success1{height: 3px;
}.success2{height: 3em;
}

六、函数                              

Less为我们提供了一个功能强大的内置函数库,其中绝大部分为颜色处理函数。下面着重介绍Misc Function中的default函数、String Function中的escape函数和颜色处理函数。

  1. default函数

示例:

// for teenager
.person(@age) when (@age <= 19) and (@age >=13){height: @age * 10px;
}
// for child
.person(@age) when (@age <13){height: @age * 6px;
}
// for adult
.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: I am 'foo'}.m('bar')                                  {case-2: I am 'bar'}.m(@x) when (isstring(@x)) and (default()) {default-string: and I am the default}&-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: I am 'foo';
}
.x-baz {default-string: and I am the default;
}

注意:

     1. default函数必须在条件控制语句当中使用;

     2. default函数可实现比else更复杂的功能,如下:

// Less源码
.mixin(@value) when (ispixel(@value)) {width: @value}
.mixin(@value) when not(default())    {padding: (@value / 5)}div-1 {.mixin(100px);
}div-2 {/* ... */.mixin(100%);
}// 最终输出:
div-1 {width: 100px;padding: 20px;
}
div-2 {/* ... */
}

  2. escape函数

顾名思义就是对字符串中的特定字符进行编码,该函数将对\<space\>#^(){}|:><;][ 和 =字符进行编码。

  3. 颜色处理函数

颜色处理函数又分为四大类:颜色定义函数(Color Definition)、颜色通道值获取函数(Color Channel)、颜色通道值修改函数(Color Operation Function)、混色函数(Color Blending)。

这里仅仅介绍常用的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。

npm install -g less

然后我们就可以通过 lessc [option option=parameter ...] <source> [destination] 的命令格式来调用lessc了!

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不太了解的可以参考《前端构建:Source Maps详解》

--source-map ,生成与生成的css同名的sourcemap文件(例如生成的css文件为main.css,那么sourcemap文件就是main.css.map),且与css文件位于同一目录下;

--source-map=<sourcemap文件路径> ,自定义sourcemap文件的路径;

--source-map-rootpath=<sourcemap文件中sources属性值的路径前缀> ,假如main.less文件位于src/less下,而生成的css和sourcemap文件位于bin/style下,那么就需要修改sourcemap文件中用于指向less文件路径的sources属性值,浏览器才能通过sourcemap文件查找到less文件。上述例子的命令为:

lessc --source-map --source-map-rootpath=../../src/less/main.less src/less/main.less bin/style/main.css

--source-map-map-inline ,以data URI Scheme的形式将sourcemap文件内容内嵌到css文件中。

--source-map-url=<css文件中指向sourcemap文件的url> ,默认情况下css文件的最后一行会插入如 /*# sourceMappingURL=main.css.map */ 的内容来指向sourcemap文件,而该选项则可修改sourceMappingURL的值。

  3. @import指令相关

--include-path=<path>[;<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安装插件 npm install -g less-plugin-clean-css ,然后通过--clean-css选项来启动CSS压缩功能。

  如: lessc file.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文件内容:

<html>
<head><title></title><link rel="stylesheet" type="text/css" href="style/main.css"/>
</head>
<body><div class="nav"></div>
</body>
</html>

样式库base.less文件内容:

.base-nav{height: 50px;background-image: url(img/nav.png);
}
.base-debug{border: solid 5px red;
}

main.less文件内容:

@import (reference) "base.less";
@env:release; //编译模式:release或debug/* 导航栏 */
.nav:extend(.base-nav){// 编译模式为debug时采用该样式& when (@env=debug){.base-debug();}
}

我们一般将工程代码级别的产出分为源码可执行代码 可发布代码 三种,而可执行代码和可发布代码的构建需求是不同的,因此构建方式也有所区别,也就是lessc使用的选项也会不同。下面将针对不同的产出物来介绍lessc的使用。

 1. 可执行代码

我将可执行代码部分再细分为release和debug两种编译模式,可以看到通过变量@env来实现不同模式下采用不同的样式规则。默认采用release模式编译源码。

lessc --include-path=lib/less --relative-urls --source-map --source-map-rootpath=../../src/less/main.less src/less/main.less bin/style/main.css

在执行lessc命令时通过选项--modify-var="env=debug"即可以debug模式编译源码。

lessc --include-path=lib/less --relative-urls --source-map --source-map-rootpath=../../src/less/ --modify-var="env=debug" src/less/main.less bin/style/main.css

可以看到上述编译过程中均会生成sourcemap文件以便调试使用。

2. 可发布代码

对于发布的内容我们会对其进行压缩处理

lessc --include-path=lib/less --clean-css="advanced" --relative-urls src/less/main.less dist/app/style/main.css

由于sourcemap文件仅在开发阶段有用,因此生成发布代码时就不要生成了。

完整的构建文件build.bat如下:

@echo off
cls
goto :%1:bin
echo Building......
::remove subitems of bin
rd /S /Q bin
::copy html files
xcopy /y src\*.html bin\
::compile less to css
cmd /C lessc --include-path=lib/less --relative-urls --source-map --source-map-rootpath=../../src/less/main.less src/less/main.less bin/style/main.css
echo Building is over!
goto :over:debug
echo Building......
::remove subitems of bin
rd /S /Q bin
::copy html files
xcopy /y src\*.html bin\
::compile less to css
cmd /C lessc --include-path=lib/less --relative-urls --source-map --source-map-rootpath=../../src/less/ --modify-var="env=debug" src/less/main.less bin/style/main.css
echo Building is over!
goto :over:dist
echo Deploying......
::remove subitems of dist
rd /S /Q dist
::copy lib
xcopy /y lib\less\img dist\lib\less\img\
::copy html files
xcopy /y src\*.html dist\app\
::compile less to css
cmd /C lessc --include-path=lib/less --clean-css="advanced" --relative-urls src/less/main.less dist/app/style/main.css
echo Deploying is over!:over

View Code

然后在CMD中输入 build bin  、 build debug  或  build dist  即可构建工程了!

sample@github

九、与Grunt结合                          

我们沿用第八节的工程目录结构来演示。

首先我们要将npm的package.json添加到工程中,然后安装grunt及其插件(grunt-contrib-less,less-plugin-clean-css,grunt-contrib-clean,grunt-contrib-copy),现在我们的工程结构应该是这样的。

sample-grunt

|-- package.json

|-- Gruntfile.js

|-- node_modules

|-- 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

其中用于将Less编译为CSS的插件为grunt-contrib-less, 下面我们对应第八章的内容来介绍该插件的选项。

   sourcemap相关:

{Boolean} sourceMap,对应lessc中属性值为true/false的--source-map选项;

{String} sourceMapFilename,对应lessc中属性值为String的--source-map选项;

{String} sourceMapRootPath,对应lessc的--source-map-rootpath选项;

{String} sourceMapURL,对应lessc的--source-map-url选项;

{Boolean} outputSourceFiles,,对应lessc的--source-map-map-inline选项;

   @import指令相关:

 {Array|String} paths,对应lessc的--include-path选项;

{Boolean} relativeUrls,对应lessc的--relative-urls选项;

   插件相关:

  {Array} plugins,数组元素为插件实例。

Gruntfile.js内容如下:

'use strict'var lessBinDebugOpts = {sourceMap: true,sourceMapRootpath: '../../'},debug = {env: 'debug'}module.exports = function(grunt){grunt.initConfig({clean: {options:{force: true},bin: ['bin'],dist: ['dist']},copy: {bin: {files: [{expand: true, cwd: 'src/', src: '*.html', dest: 'bin/'}]},dist: {files:[{expand: true, cwd: 'lib/', src: '**', dest: 'dist/lib/'},{expand: true, cwd: 'src/', src: '*.html', dest: 'dist/app'}]}    },less: {options:{paths: 'lib/less',relativeUrls: true},bin:{options: (delete lessBinDebugOpts.modifyVars, lessBinDebugOpts),files: {'bin/style/main.css': 'src/less/main.less'}},debug:{options: (lessBinDebugOpts.modifyVars = debug, lessBinDebugOpts),files: {'bin/style/main.css': 'src/less/main.less'}},dist:{options:{plugins: [new (require('less-plugin-clean-css'))({advanced: true})]},files: {'dist/app/style/main.css': 'src/less/main.less'}}}})grunt.loadNpmTasks('grunt-contrib-less')grunt.loadNpmTasks('grunt-contrib-copy')grunt.loadNpmTasks('grunt-contrib-clean')var task = function(){var name = this.name, tasks = ['clean', 'copy', 'less'], targets = tasks.map(function(v, i, m){var target = name === 'debug' && v !== 'less' ? 'bin' : namereturn v + ':' + target})grunt.task.run(targets)}grunt.registerTask('bin', task)grunt.registerTask('debug', task)grunt.registerTask('dist', task)
}

View Code

sample-grunt@github

十、总结                              

到这里我只能和大家说一声,“辛苦了各位,终于看完了耶!”。但正如标题所说,此刻无论是对less的使用,还是将其融入我们的开发工作流,我们均是入了个门而已。那应该如何进阶呢?那就是

;; 定义进阶过程
(defn becomeGeek [progress](.log js/console "实践->总结->参考最佳实践")(if (> 100 progress) (becomeGeek (+ 1 progress))));; 努力吧骚年!
(becomeGeek 1)

尊重原创,转载请注明来自:http://www.cnblogs.com/fsjohnhuang/p/4187675.html ^_^肥仔John!

如果您觉得本文的内容有趣就扫一下吧!捐赠互勉!

分类: 前端构建
好文要顶 关注我 收藏该文

^_^肥仔John
关注 - 85
粉丝 - 707

+加关注

14
0

« 上一篇:Node魔法堂:NPM入了个门
» 下一篇:前端构建:Source Maps详解

posted @ 2015-01-07 15:18 ^_^肥仔John 阅读(38255) 评论(8) 编辑 收藏
评论列表
#1楼 2015-01-07 17:31 hongyang
不错,以前接触过less,现在看来也是学到很多
支持(0)反对(0)

#2楼 2015-01-08 09:06 寻风问雨
没有什么吸引力啊,能不能整点干货呢?
css写法快不只有这种方式嘛
支持(0)反对(0)

http://pic.cnblogs.com/face/424274/20130126034040.png

#3楼 2015-09-19 16:10 冷秋月
css中的@import指令并不是说只能放在.css文件第一行,而是说一定要在所有的样式表之前使用,多个引用写多行;
这个地方的“第一行”容易让很多不了解css@import指令的人误解
支持(0)反对(0)

#4楼 2016-03-07 20:46 stoneyallen
请问下,less.watch机制可以在我更改了less中的代码后,浏览器无需刷新页面,就能显示最新的结果,这是如何实现的?
支持(0)反对(0)

http://pic.cnblogs.com/face/696637/20141219193815.png

#5楼 2016-06-20 15:08 不是苏格拉底
看extend 6.2
// 匹配失败
// 形式1,不支持以变量作入参
.son1:extend(@{p1}){}
// 形式2,不支持以变量作为选择器的规则集合
.son1:extend(.parent2){}
// 匹配成功
.son2:extend(.parent1){}

.son1:extend(.parent2){}和 .son2:extend(.parent1){}不是一回事吗?我是小白,看到这里我蒙逼了,不懂为啥第一个匹配失败,第二个就匹配成功了

支持(0)反对(0)

http://pic.cnblogs.com/face/853802/20170425114819.png

#6楼 2016-06-20 15:11 不是苏格拉底
@
我又仔细看了一遍,好像是懂了
支持(0)反对(0)

http://pic.cnblogs.com/face/853802/20170425114819.png

#7楼 2017-03-03 19:42 quliang945
非常好,正是我需要的,谢谢大佬,收藏了
支持(0)反对(0)

http://pic.cnblogs.com/face/1108721/20170221073311.png

#8楼37504662017/8/4 10:56:51 2017-08-04 10:56 WEB小飞员
bootstrap特效对照手册:http://t.cn/RK5JCg6
支持(0)反对(0)

刷新评论刷新页面返回顶部
注册用户登录后才能发表评论,请 登录 或 注册,访问网站首页。
【推荐】超50万VC++源码: 大型工控、组态\仿真、建模CAD源码2018!
【推荐】加入腾讯云自媒体扶持计划,免费领取域名&服务器
最新IT新闻:
· 十年之后,区块链将重新定义“信任”
· 今日头条首次公布算法原理 称并非一切交给机器
· 全球第一款量产「屏下指纹」手机:全面屏时代最完美的解锁方式?
· 盘点CES上的电视黑科技: 模块化电视、激光电视、柔性屏幕
· 京东宣布成立三大事业群 打造积木型组织拥抱无界零售变革
» 更多新闻...
最新知识库文章:

· 步入云计算
· 以操作系统的角度述说线程与进程
· 软件测试转型之路
· 门内门外看招聘
· 大道至简,职场上做人做事做管理

» 更多知识库文章...

公告

肥仔John@github
作品:
iScheme—Scheme解释器
本文转自

^_^肥仔John博客园博客,原文链接:http://www.cnblogs.com/fsjohnhuang/p/4187675.html,如需转载请自行联系原作者

前端构建:Less入了个门相关推荐

  1. 魔法堂:NPM入了个门

    一.前言 NPM作为Node的模块管理和发布工具,作用与Ruby的gem.Python的pypl或setuptools.PHP的pear和.Net的Nuget一样.在当前前端工程化极速狂奔的年代,即使 ...

  2. 前端构建工具gulpjs的使用介绍及技巧 (转)

    gulpjs是一个前端构建工具,与gruntjs相比,gulpjs无需写一大堆繁杂的配置参数,API也非常简单,学习起来很容易,而且gulpjs使用的是nodejs中stream来读取和操作数据,其速 ...

  3. 时下最流行前端构建工具Webpack 入门总结

    作者:wenjuanrao,腾讯 PCG 前端开发工程师 最近梳理了下以前 webpack 的相关开发经验,整理和总结了一份入门笔记,欢迎大家围观和批评指正. 随着 web 应用越来越复杂和庞大,前端 ...

  4. 前端构建新世代,Esbuild 原来还能这么玩!

    大家好,我是若川.持续组织了5个月源码共读活动,感兴趣的可以点此加我微信 ruochuan12 参与,每周大家一起学习200行左右的源码,共同进步.同时极力推荐订阅我写的<学习源码整体架构系列& ...

  5. [转]前端构建工具gulpjs的使用介绍及技巧

    本文转自:http://www.cnblogs.com/2050/p/4198792.html gulpjs是一个前端构建工具,与gruntjs相比,gulpjs无需写一大堆繁杂的配置参数,API也非 ...

  6. 前端构建工具gulpjs的使用介绍及技巧

    转载自:无双的博客园 原文地址:http://www.cnblogs.com/2050/p/4198792.html gulpjs是一个前端构建工具,与gruntjs相比,gulpjs无需写一大堆繁杂 ...

  7. docker没有下载完全_看完此文,妈妈还会担心你docker入不了门?

    上周对象突然心血来潮说想养个小宠物,我问想养啥她又说随便,你看着办!!!这我真的比较难办啊!但是咱们程序员能有个对象就不错了,还不赶紧宠着,我只能照办咯! 我去到了一家宠物店,半天也没有找到合适的目标 ...

  8. 55 前端构建工具Gulp

    技术交流QQ群:1027579432,欢迎你的加入! 欢迎关注我的微信公众号:CurryCoder的程序人生 1.第三方模块Gulp Gulp:基于node平台开发的前端构建工具. 前端构建工具:将机 ...

  9. npm run buil构建后页面白屏_从Npm Script到Webpack,6种常见的前端构建工具对比

    从Npm Script到Webpack,6种常见的前端构建工具对比 小编说:历史上先后出现了一系列构建工具,它们各有优缺点.由于前端工程师很熟悉JavaScript,Node.js又可以胜任所有构建需 ...

最新文章

  1. 西北工业大学21计算机考研,西北工业大学2018年计算机考研879专业综合考试大纲...
  2. MATLAB 数据分析方法(第2版)1.3 MATLAB基本语法
  3. Syntax error, annotations are only available if source level is 1.5 or greater.
  4. Android 代码实现整数处理为小数,Android EditText限制输入整数和小数的位数的方法示例...
  5. bash 抓捕异常_SHELL异常处理(转载)
  6. c++tcp接收文件缓存多大合适_要是有人问我 TCP, 我能怎么扯
  7. 马斯克:全力支持狗狗币主要持有者出售货币 持仓太集中是问题
  8. SAP License:客户特别总帐统驭科目某天余额取数逻辑
  9. http发送16进制报文_图解HTTP 第三章HTTP报文内的HTTP信息
  10. SQL SERVER存储过程批量插入数据库表数据
  11. linux版本i686,在Ubuntu中'i686'是什么意思? - Ubuntu问答
  12. 郑州大学计算机上机模拟题库,郑州大学VB考试模拟试题
  13. vue+element PC系统自适应
  14. [含lw+源码等]S2SH+mysql的报刊订阅系统[包运行成功]Java毕业设计计算机毕设
  15. 网页动画的12原则,帮你做出漂亮的动画效果
  16. 牛客入门编程—金字塔图案
  17. 我打不了字计算机应用怎么办,键盘正常为什么打不了字 电脑键盘失灵怎么解决...
  18. 【Matlab】帮助文档打不开
  19. 【NLP】余弦定理计算文本相似度
  20. Java图片转换为PDF并合成同一PDF

热门文章

  1. python程序设计与基础教程第六章上机实验_《Python程序设计与算法基础教程》教学大纲.doc...
  2. iwrite复制粘贴方法
  3. 信息技术社团活动点名表
  4. 六牛php工程师,童六牛——安徽工业大学材料学与工程学院教授
  5. Jenkins 配置邮件通知
  6. 扫地机器人扫水泥地板有用吗_哪位知道扫地机器人水泥地可以使用吗
  7. 用计算机画图教案评价,小学四年级信息技术优秀教学设计及评析《电脑图案设计师》...
  8. python股票价格预测_python用线性回归预测股票价格
  9. Revit二次开发 外部命令和外部应用
  10. 如何把网页传到云服务器,将网页传到云服务器