CSS预处理器
原文链接
CSS 预处理器是什么?一般来说,它们基于 CSS 扩展了一套属于自己的 DSL,来解决我们书写 CSS 时难以解决的问题:
- 语法不够强大,比如无法嵌套书写导致模块化开发中需要书写很多重复的选择器;
- 没有变量和合理的样式复用机制,使得逻辑上相关的属性值必须以字面量的形式重复输出,导致难以维护。
所以这就决定了 CSS 预处理器的主要目标:
提供 CSS 缺失的样式层复用机制、减少冗余代码,提高样式代码的可维护性。这不是锦上添花,而恰恰是雪中送炭。
Less简介
官网
Less 是一门 CSS 预处理语言,它扩展了 CSS 语言,增加了变量、Mixin、函数等特性,使 CSS 更易维护和扩展。Less 可以运行在 Node 或浏览器端。
Less安装
安装lessc
供全局使用
// 安装
npm install less -g
// 查看less版本号
lessc -v
// 将.less文件转换成.css文件
lessc xxx.less xxx.css
node环境安装
less-loader的配置详见
npm i less less-loader --save-dev
Less语法
Variables变量
1. 变量定义
变量可定义在使用前和使用后均可,变量申明可提升。但我们建议是写在less文件所有样式的最前面,便于变量的统一管理
// Variables
@color: red;
// Usage
a {
color: @color;
}
2. url中使用变量
可定义引用文件、图片等的url前缀,使用时在
""
引号内通过@{}
去使用变量
// Variables
@images: "../img";
// Usage
.less-demo {
background: url("@{images}/bg.png");
}
3. 选择器可变插值
定义变量可用于选择器和样式属性中,通过
@{}
的方式使用。可通过更改不同的less变量前缀,达到换肤的目的。
// 定义前缀
@prefix: less;
// 使用
.@{prefix}-demo {
.@{prefix}-left {}
.@{prefix}-right {}
}
// 选择器
@selector: test;
.@{selector} {
color: red;
}
// 属性
@property: color;
.top {
@{property}: red;
background-@{property}: gray;
}
4. 变量名
在变量中引用变量,通过
~"@{变量名}-属性值"
的方式实现。可用于mixins函数中,通过传递不同的参数,实现不同的样式,减少重复代码。
// 基础变量定义
@prefix:less;
@left-width: 40%;
@left-color: blue;
@right-color: red;
@right-width: 60%;
// usage
.content-color(left);
.content-color(right);
// function
.content-color(@content) {
.@{prefix}-@{content} {
// 变量定义,值根据类型有关
@content-font-color: ~"@{content}-color";
@content-width: ~"@{content}-width";
color: @@content-font-color;
width: @@content-width;
.bordered;
}
}
编译后
.less-left {
color: blue;
width: 40%;
border: 1px solid #333;
}
.less-right {
color: red;
width: 60%;
border: 1px solid #333;
}
Extend扩展
1. 扩展
A选择器想要拥有B选择器的样式,可通过
&:extend(B选择器的名称)
来实现
// h1标签扩展拥有h2标签的样式属性
h1 {
&:extend(h2);
font-size: 16px;
}
h2 {
color: #333;
}
编译后
h1 {
font-size: 16px;
}
h1, h2 {
color: #333;
}
2. 扩展all
B选择器有多个样式,想要A选择器拥有B选择器所有的样式,可通过
:extend(B选择器 all)
来实现
h2, .test-extend {
color: #333;
}
.test-extend {
font-size: 14px;
}
// 扩展某一选择器全部的样式属性
.test-expand-content:extend(.test-extend all) {
text-decoration: underline;
}
编译后
h2, .test-extend, .test-expand-content {
color: #333;
}
.test-extend, .test-expand-content {
font-size: 14px;
}
.test-expand-content {
text-decoration: underline;
}
Mixins混合
1. 选择器混合
定义class样式,可在其他样式用直接使用该样式。这种方式需要注意的是定义class样式会被输出,如果没有用到该样式,则建议不要使用定义样式的方式,生成多余的css代码。
// 会输出样式
.bordered {
border: 1px solid #333;
}
.demo {
.left {
width: 40%;
.bordered;
}
.right {
width: 60%;
.bordered;
}
}
编译后
// 如果用不到bordered这个class则会出现多余的css样式
.bordered {
border: 1px solid #333;
}
.demo .left {
width: 40%;
border: 1px solid #333;
}
.demo .right {
width: 60%;
border: 1px solid #333;
}
2. 命名空间
通过
#id名
嵌套mixin,用于区分不同库,避免多库使用时的冲突问题
#my-library {
.my-mixin() {
color: black;
}
}
// which can be used like this
.class {
#my-library > .my-mixin();
}
编译后
.class {
color: black;
}
3. 参数化混合
多参数传入时,参数可设置默认值,参数与参数直接用
;
分隔
// 不会输出样式
.color(@bg: f5f5f5; @color: #333) {
background-color: @bg;
color: @color;
}
.left {
.color();
}
.right {
.color(#f0f0f0; #666);
}
4. @arguments变量
可使用@arguments获取传入的所有参数
// 获取所有参数
.box-shadow(@x: 0; @y: 0; @blur: 5px; @color: rgba(0, 0, 0, 0.2)) {
-webkit-box-shadow: @arguments;
-moz-box-shadow: @arguments;
box-shadow: @arguments;
}
.demo{
.box-shadow(2px; 5px);
}
5. rest参数
...
代表可变个数(0-N)的参数,@rest
表示指定参数之外的剩余所有参数
.mixin(...) { // matches 0-N arguments
.mixin() { // matches exactly 0 arguments
.mixin(@a: 1) { // matches 0-1 arguments
.mixin(@a: 1; ...) { // matches 0-N arguments
.mixin(@a; ...) { // matches 1-N arguments
.mixin(@a; @rest...) {
// @rest is bound to arguments after @a
// @arguments is bound to all arguments
}
6. !important关键词
在mixin混合后用
!important
,则mixin内部的所有属性都会继承,加上!important
.foo (@bg: #f5f5f5, @color: #900) {
background: @bg;
color: @color;
}
.unimportant {
.foo();
}
.important {
.foo() !important;
}
编译后
.unimportant {
background: #f5f5f5;
color: #900;
}
.important {
background: #f5f5f5 !important;
color: #900 !important;
}
Mixin Guards防卫
通过关键字
when
,来实现有条件的执行,依据@media
执行规范。when
中的条件判断:比较运算符:>, >=, =, =<, <
,true
是唯一得“真”值。参数之间也可以进行比较。逻辑运算符:'and' ,','(相当于or),'not'
。类型校验函数:iscolor,isnumber,isstring,iskeyword,isurl
。是否包含单位函数:ispixel,ispercentage,isem,isunit
。
.mixin (@a) when (lightness(@a) >= 50%) {
background-color: black;
}
.mixin (@a) when (lightness(@a) < 50%) {
background-color: white;
}
.mixin (@a) {
color: @a;
}
detached ruleset 分离规则集
通过
@
符定义,分离规则集是一个css属性、嵌套规则集、媒体声明等的样式集合。
// declare detached ruleset
@detached-ruleset: { background: red; };
// use detached ruleset
.top {
@detached-ruleset();
}
// 函数
.desktop-and-old-ie(@rules) {
@media screen and (min-width: 1200) { @rules(); }
html.lt-ie9 & { @rules(); }
}
header {
background-color: blue;
.desktop-and-old-ie({
background-color: red;
});
}
// scope
#space {
.importer-1() {
@detached: { scope-detached: @variable; }; // define detached ruleset
}
}
.importer-2() {
@variable: value; // unlocked detached ruleset CAN see this variable
#space > .importer-1(); // unlock/import detached ruleset
}
.use-place {
.importer-2(); // unlock/import detached ruleset second time
@detached();
}
Loops循环
通过
when
判断可在函数内循环调用某一函数,直到不符合条件截止
.generate-columns(4);
.generate-columns(@n, @i: 1) when (@i =< @n) {
.column-@{i} {
width: (@i * 100% / @n);
}
.generate-columns(@n, (@i + 1));
}
输出:
.column-1 {
width: 25%;
}
.column-2 {
width: 50%;
}
.column-3 {
width: 75%;
}
.column-4 {
width: 100%;
}
Merge合并属性
通过
+
和+_
进行样式合并,前者用逗号隔开,后者用空格隔开
// merge需要配置+和+_实现
.mixin() {
box-shadow+: inset 0 0 10px #555;
}
.myclass {
.mixin();
box-shadow+: 0 0 20px black;
}
.mixin() {
transform+_: scale(2);
}
.myclass {
.mixin();
transform+_: rotate(15deg);
}
输出:
.myclass {
box-shadow: inset 0 0 10px #555, 0 0 20px black;
}
.myclass {
transform: scale(2) rotate(15deg);
}
Parent Selectors父选择器&
.header {
& &-title {
}
&-title {
}
&:first-child {
}
.less & {
}
& & {
}
}
编译后
.header .header-title {
}
.header-title {
}
.header:first-child {
}
.less .header {
}
.header .header {
}
@plugin插件
@plugin "my-plugin";定义一个插件JS文件,返回一个Less节点。可定义不同文件得重名得函数,在插件引用作用域中用。return false可调用该函数但不返回任意值。3.0版本之后,函数可返回任意类型。
// function.js
module.exports = {
install(less, pluginManager, functions) {
// 将传入的参数以,分割返回
functions.add('args', node => {
if (typeof node.value === 'string') {
return node.value;
}
let result = [];
for (let i = 0; i < node.value.length; i++) {
result.push(node.value[i].value);
}
return result.join(', ');
});
}
};
// usage
@plugin "./functions";
.transition(...) {
transition-property: args(@arguments);
transition-duration: 0.2s;
}
Less常用的语法就总结到这里啦!哪里不对的欢迎指出哦~~
又是有收获的一天!🆙
参考文章: