前端构建:Less入了个门
Posted X-JoNNeY
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了前端构建:Less入了个门相关的知识,希望对你有一定的参考价值。
一、前言
说到前端构建怎能缺少CSS预处理器呢!其实CSS的预处理器有很多啦,比较出名的有Scss、Sass、Stylus和Less。(最近还听说出现了Autoprefixer等CSS后处理器,可参考@一丝的PPT)
众多CSS预处理器中Less的语法最接近原生CSS,因此相对来说更容易上手,假如有JS、C#等编程经验的话,其实上述的几种预处理器的学习成本也不会特别高。下面是我们这阵子的学习笔记,以便日后查阅。
最好的入门教程——官网地址:http://lesscss.org/
最佳实践之一——Bootstrap
由于内容较多,特设目录一坨:
6.1. 父选择器必须严格匹配,除了属性选择器中属性值引号不必匹配外,或添加all关键字外。
6.3.1. media query内的extend操作,仅能继承当前块的其他选择器样式。
6.3.2. 非media query内的extend操作,将会继承所有media query中匹配的选择器样式。
7.1. 类选择器、ID选择器自动被定义为mixin,而且具有命名空间;
7.2. 显示定义不带参数和带参数的样式库(mixin库),不会输出到最终输出中,仅供调用;
7.3. mixin的中内置两个特殊的对象@arguments和@reset。@argumentsk代表mixin的所有入参,而@reset代表mixin的...入参数组。
7.4. mixin的重载可定义多个同名mixin,调用时只要参数数量匹配则会执行相应的mixin。
搭建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"/>
// 单行注释,不会作为最终输出
/*
多行注释,以原生CSS的/*注释....*/形式作为最终输出
*/
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: \': 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;
}
Less源码:
.main{
padding: 10px;
> div {
width: 100px;
}
.aside {
width: 200px;
}
}
最终输出:
.main {
padding: 10px;
}
.main > div {
width: 100px;
}
.main .aside {
width: 200px;
}
- 采用&引用完整的父选择器
- 可通过追加和预追加的方式加工&,从而生成新的选择器
- 通过
&::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;
}
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) "文件路径";
- 表示对同一资源可引入多次。
有两种语法形式, <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;
}
注意事项:
*.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;
}
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.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的功能。
Mixin相当于macro,会将样式规则内联到调用的位置中。而Less中的mixin有以下的注意点:
.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;
}
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函数和颜色处理函数。
示例:
// 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 {
以上是关于前端构建:Less入了个门的主要内容,如果未能解决你的问题,请参考以下文章