最近在公司给同事们分享了一下postcss,在这里做一个简单总结:
在我们日常写css的过程中,一般会有哪些觉得比较繁琐的地方??
这里我列举我自己日常开发中觉得比较繁琐的几点:
- 前缀问题;
- 有时候为了规范或是精确性我们会写一些比较深的选择器;
- 在不确定一些css属性兼容性的时候,我们经常需要查询一些属性的浏览器兼容性;
上面提到的问题,postcss中都有相应的插件可以帮我们解决对应的问题,下面的问题是,postcss是什么?
在看一些讲postcss的文章里,会说明postcss不是类似sass、less的预处理器,也不是后处理器,那postcss到底是什么?这时候。。。直接看API:
上面列举的是api中一些基本的类说明(详细api移步:http://api.postcss.org/),结合postcss文档中说明的postcss的工作流:
workflow:
Core Structor
总结说明:
postcss处理css的方式,主要区分三部分:
- parser过程:将css字符串解析成可供我们操作的JavaScript对象
- processor过程:我们应用postcss插件、或是自定义插件,都是在这个过程中,根据postcss提供的API,对parser生成的js对象做相应调整;
- stringfier过程:将我们处理后的js对象,再转换回为css字符串
下面通过具体的代码说明一下postcss 对css的转换:
npm 安装postcss、代码如下:
var postcss = require('postcss')
var root = postcss.parse('a{color:white;} b{width:100px}')
返回的root对象的内容为下图:
由上图可以看到,root对象是我们css代码结构化生成的js对象,里边对应包含我们的选择器、css属性名、属性值等等(图中标示了一些很容易理解的信息,想要了解详细可以移至官方api:http://api.postcss.org/),经过这一步之后,我们可以操作这个js对象,做出一切我们想要的改变,然后再由stringfile转换为最终的css代码。
有了上面这些,在使用postcss的时候,就有了一些基本的认知。下面介绍几款常用的插件:
插件
Autoprefixer:
这应该是postcss最广为人知的一个插件了 ,这个插件可以:
-
可以指定浏览器版本、范围
- 在插件参数中指定
- use .browserslistrc config
- package.json with browserslist key
- 去除过时的前缀
precss
这款插件类似less、sass ,可以让我们在css中使用变量、css嵌套、函数、mixin
除了precss,还有很多细粒度的插件,比如:
- postcss-nested:专门支持css嵌套写法:
- postcss-define-function :实现类似sass 函数功能
- postcss-for:专门增加循环支持
- ...
doiuse:
可以为我们检查浏览器支持
cssnano:
css压缩(会进行一些合并转换操作 ,示例会说明)
详细插件列表及分类,请移至:https://github.com/postcss/po...
代码示例:
说明:示例基于gulp+gulp-postcss
npm安装好gulp、gulp-postcss以及对应的插件,下面的实例使用到postcss-nested、cssnano、postcss-apply、autoprefixer、gulp-rename
gulpfile.js:
var gulp=require('gulp')
var postcss=require('gulp-postcss')
var nested=require('postcss-nested')
var cssnano=require('cssnano')
var apply=require('postcss-apply')
var autoprefixer=require('autoprefixer')
var rename=require('gulp-rename')
var option={
browsers: ['Opera 12', 'IE 8']
}
gulp.task('postcss',function() {
return gulp.src('./test.pcss').pipe(postcss([autoprefixer(option),apply,nested])).on('error',function(error) {
console.log(error)
this.end()
}).pipe(rename({extname:'.css'})).pipe(gulp.dest('./'))
})
上面我们指定使用的浏览器,只是示例,使用'Opera 12', 'IE 8'这样的组合,我们的源文件为test.pcss(这里我使用webstorm安装了postcss相关插件,.pcss后缀表示postcss样式文件,避免编辑器的语法错误提示),使用gulp-rename插件,最终生成的文件为当前目录下的test.css,执行任务,这里贴出源文件与生成后的文件对比:
由上面的对比,我们可以看出autoprefixer 自动增加/删除(当然也可以设置不删除) 前缀的功能,以及嵌套等的使用,下面一个问题:关于浏览器的兼容性检查呢?
使用doiuse,代码如下:
gulp.task('doiuse',function() {
var option={
browsers: [
'ie >= 6',
],
onFeatureUsage: function (usageInfo) {
console.log(usageInfo.message)
}
}
gulp.src('./test.css').pipe(postcss([doiuse(option)]))
})
给出运行结果的部分截图:
这里我们选择的浏览器范围是‘ie>=6’,doiuse执行的结果会告诉我们css3 transition 并不被ie一些版本的浏览器支持。这样我们就可以精确、统一地为我们的css进行浏览器兼容检查。
最后一步:压缩:
代码:
gulp.task('cssnano',function() {
gulp.src('./test.css').pipe(postcss([cssnano])).pipe(gulp.dest('./'))
})
上面test.css文件生成的结果如下:
这里提醒大家注意的是,我们原本css文件中,样式分开写的部分,cssnano为我们做了合并操作,颜色属性的属性值部分,也换成了字节数比较少的16进制表示法。为我们的css文件减少了一部分大小。
写一个插件
对于插件的编写文档也很详细,这里给一个自己日常用的简单示例,最近在写一个小程序项目,写小程序样式时使用一个单位:rpx,结合日常的编码习惯,写这个单位觉得异常别扭,于是写了一个针对特定属性自动加单位的插件,代码如下:在gulpfile.js里增加如下代码:
function addunit(root) {
// Transform CSS AST here
var needAddProperties = ['width', 'height', 'top', 'left', 'bottom', 'right', 'margin-top',
'margin-bottom', 'margin-left', 'margin-right',
'padding-right', 'padding-left', 'padding-top', 'padding-bottom']
root.walkDecls(function(decl) {
if (needAddProperties.indexOf(decl.prop)!= -1) {
decl.value.indexOf('%')== -1 && decl.value.indexOf('rpx')== -1 && (decl.value += 'rpx')
}
})
}
gulp任务中 postcss插件数组末尾增加一个自己写的插件 addunit:
gulp.task('postcss', function() {
return gulp.src('./testaddunit.pcss').pipe(postcss([autoprefixer(option), apply, nested, addunit]))
.on('error', function(error) {
console.log(error)
this.end()
}).pipe(rename({ extname : '.css' })).pipe(gulp.dest('./'))
})
处理文件的前后对比如下:
处理过程会根据需要自动为我们添加单位。在实际开发中再配合postcss-scrib,我们是可以这样写代码的:
这里使用postcss-scrib插件我们可以为属性自定义别名,结合gulp的watch功能,实时为我们生成对应的css文件,也没有了编辑器语法错误提示,写css一下子美好了很多。。。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。