CSS预处理器LESS

时间:2022-02-23 13:52:43
CSS预处理器
定义:CSS预处理器定义了一种新的语言,其基本思想是,用一种专门的编程语言,为CSS增加了一些编程的特性,将CSS作为目标生成文件,然后开发者就只要使用这种语言进行编码。
---文译参考:https://www.w3cplus.com/css/css-preprocessor-sass-vs-less-stylus-2.html
列举:Less,Sass,Stylus,Scss等
http://lesscss.org/
http://sass-lang.com/
http://learnboost.github.com/stylus

LESS扩充了CSS语言,增加了诸如变量、混合(mixin)、函数等功能,让 CSS 更易维护、方便制作主题、扩充。
LESS 可以运行在 Node、浏览器和 Rhino 平台上。网上有很多第三方工具帮助你编译 Less 源码。

LESS安装分为两种:客户端和服务器端安装。
a) 直接在客户端使用“.less”(LESS源文件),只需要在官网载一个Javascript脚本文件主“less.js”,然后在我们需要引入LESS源文件的HTML的<head>中加入如下代码:
<link rel="stylesheet/less" type="text/css" rel="external nofollow" href="文件路径/styles.less">
<script src="文件路径/less.js" type="text/javascript"></script>	
需要注意的是:在引入“.less”文件中,“link”的“rel”属性要设置为“stylesheet/less”。
还有更重要的一点需要注意的是:LESS源文件一定要在“less.js”引入之前引入,这样才能保证LESS源文件正确编译解析。
b) 服务器端安装
LESS在服务器端的使用主要是借助于LESS的编译器,将LESS源文件编译生成最终的CSS文件,目前常用的方式是利用node的包管理器(npm)安装LESS,安装成功后就可以在Node环境中对LESS文件进行编译。如此一来,LESS在服务器的安装和Sass的安装有点相似,不同之处是他们需依赖的环境不一样,LESS需要的是Node JS环境,而Sass需要的是Ruby环境,为了让大家能更清晰的知道如何在服务器端安装LESS,此处简单的过一下安装过程(本文演示的是在Window7下的安装方法)。
 npm install less  // npm install less@latest

LESS文件的转译成CSS文件
在安装的Node JS环境下通过其自己的命令来进行转译
$lessc style.less
上面的命令会将编译的CSS传递给stdout,可以将其保存到一个文件中:
$lessc style.less>style.css

除了上面的命令转译LESS源文件之外,现在还有很多第三方开发的工具,比较常见的有:SimpleLess、Less.app、LESS编译辅助脚本-LESS2CSS、WinLess和CodeKit.app等,我个人现在常用的是WinLess工具,简单易用,不过在IOS系统下LESS.app和CodeKit.app很好用。

LESS语法
LESS是CSS的一种扩展形式,它并没有阉割CSS的功能,而是在现有的CSS语法上,添加了很多额外的功能。就语法规则而言,LESS和Sass一样,都是使用CSS的标准语法,只是LESS的源文件的扩展名是“.less”,其基本语法类似于:
/*style.less*/
h1 {
  color: #963;
  background-color: #333;
}
LESS特性:变量、混入、嵌套、函数等。
CSS预处理器语言支持任何变量(例如:颜色、数值、文本)。然后你可以在任意地方引用变量。

*以@作为变量的起始标识,变量名由字母、数字、_和-组成
*没有先定义后使用的规定;
*以最后定义的值为最终值;
*可用于rule值、rule属性、rule属性部件、选择器、选择器部件、字符串拼接;
*定义时 "@变量名: 变量值;" 的形式;引用时采用 "@变量名" 或 "@{变量名}" 的形式;

*存在作用域,局部作用域优先级高于全局作用域。

 @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. 以最后定义的值为最终值;

转译出来的CSS样式:

.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;
}

作用域(Scope)

CSS预处理器语言中的变量和其他程序语言一样,可以实现值的复用,同样它也存在生命周期,也就是Scope(变量范围,开发人员习惯称之为作用域),简单点讲就是局部变量还是全局变量的概念,查找变量的顺序是先在局部定义中找,如果找不到,则查找上级定义,直至全局。
LESS中的作用域和其他程序语言中的作用域非常的相同,他首先会查找局部定义的变量,如果没有找到,会像冒泡一样,一级一级往下查找,直到根为止。
/*LESS样式*/
@color: black;
.scoped {
  @bg: blue;
  @color: white;
  color: @color;
  background-color:@bg;
}
.unscoped {
  color:@color;
}
转译出来的CSS样式:
.scoped {
  color:white;/*白色(调用了局部变量)*/
  background-color:blue;
}
.unscoped {
  color:black;/*黑色(调用了全局变量)*/
}	
混合(Mixins)
Mixins是CSS预处理器中语言中最强大的特性,简单点来说,Mixins可以将一部分样式抽出,作为单独定义的模块,被很多选择器重复使用。平时你在写样式时肯定有碰到过,某段CSS样式经常要用到多个元素中,这样你就需要重复的写多次。在CSS预处理器语言中,你可以为这些公用的CSS样式定义一个Mixin,然后在你CSS需要使用这些样式的地方直接调用你定义好的Mixin。这是一个非常有用的特性,Mixins被当作一个公认的选择器,还可以在Mixins中定义变量或者默认参数。
在LESS可以将Mixins看成是一个类选择器,当然Mixins也可以设置参数,并给参数设置默认值。不过设置参数的变量名是使用“@”开头,同样参数和默认参数值之间需要使用冒号(:)分隔开。
在LESS样式中定义一个名叫“error”的Mixin,这个“error”设置了一个参数“@borderWidth”,在没有特别定义外,这个参数的默认值是“2px”:
/*声明一个Mixin叫作“error”*/
.error(@borderWidth:2px){
  border:@borderWidth solid #f00;
  color: #f00;
}
/*调用error Mixins*/
.generic-error {
  .error();/*直接调用error mixins*/
}
.login-error {
  .error(5px);/*调用error mixins,并将参数@borderWidth的值重定义为5px*/
}	
转换后的代码:
.generic-error {
  border: 2px solid #f00;
  color:#f00;
}
.login-error {
  border:5px solid #f00;
  color: #f00;
}

父选择器引用(ParentSelector)

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

/* 
 * 采用&引用完整的父选择器
 * 可通过追加和预追加的方式加工&,从而生成新的选择器
 * 通过&::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;
 }
}
转译出来的CSS代码:
/* 
 * 采用&引用完整的父选择器
 * 可通过追加和预追加的方式加工&,从而生成新的选择器
 * 通过&::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;
}

嵌套(Nesting)

CSS预处理器语言中的嵌套指的是在一个选择器中嵌套另一个选择器来实现继承,从而减少代码量,并且增加了代码的可读性。比如说,我们在CSS中多个元素有一个相同的父元素,那么写样式会变得很乏味,我们需要一遍一遍的在每个元素前写这个父元素,除非给特定的元素添加类名“class”或者ID。
section {
  margin:10px;
}
section nav {
  height:25px;
}
section nav a {
  color: #0982c1;
}
section nav a:hover {
  text-decoration: underline;
}	
相反,使用CSS预处理器语言的嵌套特性,我们可以在父元素的大括号({})里写这些元素。同时可以使用“&”符号来引用父选择器。
section {
  margin:10px;
  nav {
    height:25px;
    a {
      color:#0982c1;
      &:hover {
        text-decoration:underline;
      }
    }
  }
}	
继承(Inheritance)
对于熟悉CSS的同学来说,对于属性的继承并不陌生。平时在写CSS样式常碰到多个元素应用相同的样式时,我们在CSS中通常都是这样写:
p,ul,ol{/*样式写在这里*/}
LESS将Mixins中的样式嵌套到每个选择器里面。这种方法的缺点就是在每个选择器中会有重复的样式产生。
.block {
  margin: 10px 5px;
  padding: 2px;
}
p {
  .block;/*继承.block选择器下所有样式*/
  border: 1px solid #eee;
}
ul,ol {
  .block; /*继承.block选择器下所有样式*/
  color: #333;
  text-transform: uppercase;
}

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

.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;
}

转译出来的CSS代码:

.animal,
.bear,
.deer {
 color: #fff;
}
/* 语法1:<selector>:extend(<parentSelector>){} */
.bear {
 width: 100px;
 height: 100px;
}
/* 语法2:<selector>{ &:extend(<parentSelector>); } */
.deer {
 width: 50px;
 height: 50px;
}
注意事项:
 1. 父选择器必须严格匹配,除了属性选择器中属性值引号不必匹配外,或添加all关键字外。
*.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){}
转译后的CSS代码
*.parent,
*.son {
 height: 100px;
}
*.parent .hair,
*.son .hair {
 color: #f27;
}
*.parent [name=eyes],
.son,
.son,
*.son [name=eyes] {
 color: #768;
}
2. 父选择器不支持变量形式
@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){}
转译后的CSS代码
.parent1,
.son2,
.son3 {
 height: 100px;
}
.parent2 {
 height: 200px;
}
3. media query影响继承的作用域
3.1. media query内的extend操作,仅能继承当前块的其他选择器样式。
注意:不能extend当前media query块内部的子media query块中的选择器样式;但可以extend父media query块的选择器样式。
.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;
 }
 }
}
转译后的CSS代码
.parent1 {
 height: 200px;
}
@media screen {
 .parent1 {
 height: 100px;
 }
}
@media screen and (min-width: 1023px) {
 .parent2 {
 width: 200px;
 }
}
3.2. 非media query内的extend操作,将会继承所有media query中匹配的选择器样式。
@media screen{
  .parent{
   height: 100px;
 }
 @media (min-width: 1023px){
   .parent{
   width: 200px;
 }
 }
}
.son:extend(.parent){}
转译后的CSS代码
@media screen {
 .parent,
 .son {
 height: 100px;
 }
}
@media screen and (min-width: 1023px) {
 .parent,
 .son {
 width: 200px;
 }
}
>> 增强的mixin定义mixin时仅能使用类选择器和ID选择器,而extend操作可对应所有的选择器,因此当没有动态入参而又需要类选择器和ID选择器以外的选择器时,可使用extend来实现mixin的功能。

运算符(Operations)

CSS预处理器语言还具有运算的特性,其简单的讲,就是对数值型的Value(如:数字、颜色、变量等)进行加减乘除四则运算。这样的特性在CSS样式中是想都不敢想的,但在CSS预处理器语言中对样式做一些运算一点问题都没有了
@base_margin: 10px;
@double_margin: @base_margin * 2;
@full_page: 960px;
@half_page: @full_page / 2;
@quarter_page: (@full_page / 2) / 2;
声明一下,在取得“@quarter_page”变量时,我们可以直接除以4,但是在这里,我们只是想演示一下圆括号组成的“运算顺序”(这个运算顺序小学生也知道)。在复合型运算中,小括号也是很有必要的,例如:
border: (@width / 2) solid #000;
LESS颜色函数是CSS预处理器语言中内置的颜色函数功能,这些功能可以对颜色进行处理,例如颜色的变亮、变暗、饱和度控制、色相控制,渐变颜色等处理十分的方便。
lighten(@color, 10%); /* 返回的颜色在@color基础上变亮10% */
darken(@color, 10%);  /* 返回的颜色在@color基础上变暗10%*/
saturate(@color, 10%);   /* 返回的颜色在@color基础上饱和度增加10% */
desaturate(@color, 10%); /* 返回的颜色在@color基础上饱和度降低10%*/
spin(@color, 10);  /* 返回的颜色在@color基础上色调增加10 */
spin(@color, -10); /* 返回的颜色在@color基础上色调减少10 */
mix(@color1, @color2); /* 返回的颜色是@color1和@color2两者的混合色 */	
下面是LESS中如何使用一个颜色函数的简单例子:
@color: #0982C1;
h1 {
  background: @color;
  border: 3px solid darken(@color, 50%);
}
导入(Import)
CSS中,并不喜欢用@import来导入样式,因为这样的做法会增加http的请求。但是在CSS预处理器中的导入(@import)规则和CSS的有所不同,它只是在语义上导入不同的文件,但最终结果是生成一个CSS文件。
被导入文件的样式:
/* file.{type} */
body {
  background: #EEE;
}
需要导入样式的文件:
@import "reset.css";
@import "file.{type}";
p {
  background: #0982C1;
}
转译出来的CSS代码:
@import "reset.css";
body {
  background: #EEE;
}
p {
  background: #0982C1;
}	
@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) "文件路径"; 

  表示对同一资源可引入多次。

注释(Comment)

CSS预处理器语言中的注释是比较基础的一部分,这三款预处理器语言除了具有标准的CSS注释之外,还具有单行注释,只不过单行注释不会被转译出来。  

CSS预处理器的高级应用
LESS还拥有一些很有趣的特性有助于我们的开发,例如条件语句、循环语句等。
在编程语言中常见的条件语句: if/else if/else

LESS的条件语句使用有些另类,他不是我们常见的关键词if和else if之类,而其实现方式是利用关键词“when”
.mixin (@a) when (@a >= 10) { 
  background-color: black; 
 } 
 .mixin (@a) when (@a < 10) { 
  background-color: white; 
 } 
 .class1 { .mixin(12) } 
 .class2 { .mixin(6) }	
转译出来的CSS:
.class1 { 
  background-color: black; 
 } 
.class2 { 
  background-color: white; 
 }
利用When以及<、>、=、<=、>=是十分简单和方便的。LESS并没有停留在这里,而且提供了很多类型检查函数来辅助条件表达式,例如:iscolor、isnumber、isstring、iskeyword、isurl等等。
.mixin (@a) when (iscolor(@a)) { 
  background-color: black; 
 } 
 .mixin (@a) when (isnumber(@a)) { 
  background-color: white; 
 } 
 .class1 { .mixin(red) } 
 .class2 { .mixin(6) }	
转译出来的CSS:
.class1 { 
  background-color: black; 
 } 
 .class2 { 
  background-color: white; 
 }	

另外,LESS的条件表达式同样支持AND和OR以及NOT来组合条件表达式,这样可以组织成更为强大的条件表达式。需要特别指出的一点是,OR在LESS中并不是or关键词,而是用来表示or的逻辑关系。

.smaller (@a, @b) when (@a > @b) { 
  background-color: black; 
} 
.math (@a) when (@a > 10) and (@a < 20) { 
  background-color: red; 
} 
.math (@a) when (@a < 10),(@a > 20) { 
  background-color: blue; 
} 
.math (@a) when not (@a = 10)  { 
  background-color: yellow; 
} 
.math (@a) when (@a = 10)  { 
  background-color: green; 
} 

.testSmall {.smaller(30, 10) } 
.testMath1 {.math(15)} 
.testMath2 {.math(7)} 
.testMath3 {.math(10)}
转译出来的CSS:
.testSmall { 
  background-color: black; 
} 
.testMath1 { 
  background-color: red; 
  background-color: yellow; 
} 
.testMath2 { 
  background-color: blue; 
  background-color: yellow; 
} 
.testMath3 { 
  background-color: green; 
}
b)循环语句
LESS并没支持for循环语句,但值得庆幸的是,在LESS中可以使用When来模拟出for循环的特性。
.loopingClass (@index) when (@index > 0) {
  .myclass {
    z-index: @index;
  }
  // 递归
  .loopingClass(@index - 1);
}
// 停止循环
.loopingClass (0) {}
// 输出
.loopingClass (3);
转译出的CSS:
.myclass {z-index: 3;}
.myclass {z-index: 2;}
.myclass {z-index: 1;}	

参考引用:https://www.w3cplus.com/css/css-preprocessor-sass-vs-less-stylus-2.html
参考引用:http://www.jb51.net/article/107875.htm#a2