一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第16天,点击查看活动详情。
预编译的原理都是通过能读取文件的语言编写的插件把文件解析成css文件,因为他们的文件名都不是纯css,写法也不是纯css,是无法被浏览器识别的,所以写完需要编译一下才能使用,这就是预编译。
css的不足,没有变量,不支持嵌套,编程能力较弱,代码复用性差。导致写出来的css维护性极差
三个最常见的css预编译工具
-
sass,目前受less影响,已经进化到了全面兼容css的scss(scss需要使用分号和花括号而不是换行和缩进)
- npm下载命令,通过命令去编译,改一次就得编译一次
- 上面的命令有个
watch方法可以监听文件夹变化 - 用考拉工具实时编译
- 用编辑器【hbuilder,vs,webstrom】都是有自带的实时编译工具的,自行百度
- 用代码编译框架编译【gulp,grunt,webpack】
-
less,受sass影响较大,但又使用css的语法,让大部分开发者和设计师更容易上手,缺点是比起sass,可编程功能不够,优点是简单和兼容css
- npm下载命令,通过命令去编译,改一次就得编译一次
- 用考拉工具实时编译
- 用编辑器【hbuilder,vs,webstrom】都是有自带的实时编译工具的,自行百度
- 用代码编译框架编译【gulp,grunt,webpack】
-
stylus,主要用来给Node项目进行css预处理支持。
- npm下载命令,通过命令去编译,改一次就得编译一次
- 上面的命令有个
-w方法可以监听文件夹变化 - 用代码编译框架编译【gulp,grunt,webpack】
简单的对比一下:
Less & SCSS:
.wrap {
display: block;
}
Sass:
.wrap
display: block
Stylus:
.wrap
display block
sass最开始通过缩进、空格、换行的形式来控制层级关秀,后来又支持了传统的类css语法的scss。less中规中矩,使用css的风格,对新手非常友好,也利于现有项目的迁移。stylus既可以使用csaa风格的语法来编写,也兼容css的风格。
三者都支持变量的定义,而定义方式又各不相同:
Less:
@smallFont: 12px;
small{
font-size: @smallFont;
}
Sass:
$smallFont: 12px;
small {
font-size: $smallFont;
}
Stylus:
smallFont = 12px
small
font-size smallFont
/*Stylus中声明的变量,如果变量名跟css中的字面值相同时,会覆盖css中的字面值*/
css变量的作用范围,sass和stylus是相同的,less是另一种情况:
Less:
@color:red;
.content-1{
color: @color;
}
@color:black;
.content-2{
color:@color;
}
/*编译出的css*/
.content-1{
color: black;
}
.content-2{
color: black;
}
/*Less中的变量,在声明中使用时,如果出现多次赋值的情况,回去最后一次赋值的值。会带来隐患:如果不同的组件库或类库使用了相同的变量名,那么就会出现覆盖的情况,所以应该采用模块化的方式*/
Sass:
$color: red;
.content-1{
color:$color;
}
$color: black;
.content-1{
color:$color;
}
Stylus:
color = red;
.content-1
color color;
color = black;
.content-2
coloe color;
/*编译出来的css*/
.content-1{
color: red;
}
.content-2{
color: black;
}
/*Sass或Stylus中的变量,如果出现多次赋值的情况,会取声明前面最近的一次赋值的值*/
Sass、Stylus中提供了“不存在即赋值”的变量声明;
Sass:
$a: 1;
$a: 5 !default;
$b: 3 !default;
//$a = 1,$b = 3
Stylus:
a = 1
a := 5
b = 3
//a = 1,b = 3
/*使用“不存在即赋值”语法,编译器会检查前面是否定义了同名变量,如果没有定义,执行变量定义;如果前面定义了同名变量,则不会执行这个赋值的操作。
因此在引入之前定义好需要同名变量,就能达到目的了*/
我们定义的变量不仅能用作css声明的值,同事也能嵌套到选择器及属性中:
Less:
@profix: ui;
@prop: background;
.@{prefic}-button {
@{prop}-color:red;
}
Sass:
$prefix: ui;
$prop: background;
.#{$prefix}-button{
#{$prop}-color: red;
}
Stylus:
prefix = ui
prop = background
.{prefix}-button
{prop}-color red
样式复用,mixin和集成。对于mixin,这三个预编译器有不同的实现方式:
Less:
.mixin-style(@color: red) {
color: @color;
}
.content {
.mixin-style(red);
}
Sass:
@mixin mixin-style {
color: red;
}
.content {
@include mixin-style;
}
Stylus:
mixin-style(color)
color color
.content
mixin-style(red) // or mixin-styls red 透明mixin
Less中直接引入一个CSS的class作为mixin(不推荐),同时也提供上面的能传入参数的mixin;Sass通过@mixin和@include的方式定义和引入mixin;Stylus不需要显示声明的mixin,同时还提供透明迷信的功能,就像属性一样引入。
\
Sass、Stylus通过@extend关键字来继承样式,二Less通过伪类的方式还是来继承:
Sass/Stylus:
.message{
padding: 10px;
border: 1px solid #eee;
}
.warning{
@extend .message;
color: #e2e21e;
}
Less:
.message {
padding: 10px;
border: 1px solid #eee;
}
.warning {
&:extend(.message);
color: #e2e21e;
}
PostCSS
是一个使用js插件来转换样式的工具。PostCSS的作用主要有lint 揣手手,支持CSS Next语法,自动添加前缀等功能。通过插件,基本上可以覆盖CSS预处理器的功能,同时实现多得多的预处理器实现不了的功能。
1、PostCSS不是CSS预处理器的替代品
2、PostCSS的优势在于其丰富的插件生态,能够覆盖开发中的方方面面,我们又能够很容易的开发自己的插件。同时又因为PostCSS使用JavaScript,JS本身及其繁荣的生态,为PostCSS提供了强大的能力。
3、PostCSS中,最为大家所熟知的就是Autoprefix,在大量的预处理中使用。PostCSS依靠其现代化的架构设计,甩掉了历史包袱,利用其插件系统,更加优雅强化CSS的健壮性。
PostCSS架构大致为:
通过PostCSS将CSS转换成AST(抽象语法树),对应的是JavaScript对象;然后通过插件遍历AST,进行增加,删除,修改;最后再生成CSS文件,这就是整个流程,跟babel的架构相似。
解析和系列化生成CSS,PostCSS已经帮我们做好了,我们只需要关注在插件开发,以及如何操作AST。
.content{
color:red;
}
如果我们检测到某个样式中有“color:red”这样一条样式规则,需要自动增加“background-color:red”这样一条规则。
PostCSS官方提供插件编写的模板,只需要将其下载下来:
git clone git@github.com:postcss/postcss-plugin-boilerplate.git
然后进入该文件夹的目录下,输入命令:
node start
这个时候需要你输入一些信息,然后就会自动生成一个插件的模板文件夹,还是进入到这个对应的文检查下,这时就可以看到熟悉的package.jsob,index.js等文件,使用npm安装了依赖之后就可以在index.js文件中编写插件的逻辑了。同样的,我们可以在项目中通过npm安装任意依赖,然后在index.js中通过require引入,这就是背靠JavaScript的又是。
index.js默认的内容是这样的:
var postcss = require('postcss');
module.exports = postcss.plugin('postcss-practice', function (opts) {
opts = opts || {};
// Work with options here
return function (root, result) {
// Transform CSS AST here
};
});
编写出出来的插件代码是这样的:
const postcss = require('postcss');
const postcss = require('postcss');
module.exports = postcss.plugin('postcss-practice', function (opts) {
opts = opts || {};
console.log(opts);
// Work with options here
return function (root) {
root.walkRules(rule => {
console.log(rule.selector);
rule.walkDecls(decl => {
if (
decl.prop === 'color' &&
decl.value === 'red'
) {
rule.append({
prop: 'background-color',
value: 'red'
});
}
});
});
};
});
//root.walkRules会遍历每一个css规则,可以通过rule.selector拿到内衣组规则中的选择器,然后通过rule.walkDecls
//遍历每一组规则中的样式声明,通过decl.prop,decl.value拿到样式声明中的属性和值。如果满足条件则向规则中插入一条
//新的样式声明。
插件编写完了,样板项目中还包含index.test.js来测试插件是否合理。
var postcss = require('postcss');
var plugin = require('./index.js');
function run(input, output, opts) {
return postcss([ plugin(opts) ]).process(input)
.then(result => {
expect(result.css).toEqual(output);
expect(result.warnings().length).toBe(0);
});
}
// Write tests here
it('does something', () => {
return run('a{color: red;}',
'a{color: red;background-color: red;}', {});
});
然后是运行:“npm ren test”的结果
接下来就可以打包发布,然后在项目中安装使用了,就像其他插件那样。PostCSS还提供了许多有用的函数,帮助你操作AST,轻松完成开发。