今天闲来无聊,重新来说说CSS3前缀的问题。在春节前和@一丝姐姐说起Sass中有关于 gradient 的mixins。姐姐说:
为什么还要用mixin呢?为什么为使用 Autoprefixer ?使用Autoprefixer,只需要输入一行代码,编译器帮你做了一切,还纠结个毛mixin。
姐姐的一句话让我汗颜,我还在思考着如何让Sass来写Gradient,或者类似这样需要带前缀的CSS3属性。也这样让我在思考,那么有了Autoprefixer这样的后处理,Sass中有关于CSS3的mixins是不是已失去了他存在的意义。带着这样的为什么?我们一起来开启今天有关于CSS3前缀的探讨。
使用过CSS3属性的同学都知道,CSS3属性都需要带各浏览器的前缀,甚至到现在,依然还有很多属性需要带前缀。这是为什么呢?
我的理解是,浏览器厂商以前就一直在实施CSS3,但它还未成为真正的标准。为此,当一些CSS3样式语法还存在波动时,它们提供针对流星器的前缀。现在主要流行的浏览器内核主要有:
而这些不同内核的浏览器,CSS3属性(部分需要添加前缀的属性)对应需要添加不同的前缀,也将其称之为浏览器的私有前缀,添加上私有前缀之后的CSS3属性可以说是对应浏览器的私有属性:
-ms
-moz
-o
-webkit
来看一个简单的示例,早期写一个圆角 border-radius
,需要这样写:
.box { -moz-border-radius: 5px; -webkit-border-radius: 5px; -o-border-radius: 5px; border-radius: 5px; }
这样编写代码,无形之中给前端人员增加了不少工作量,于是开始有人在讨论这个问题“如何在编写CSS时不需要添加浏览器的私有前缀,又能让浏览器识别?”
为了解决手工书写前缀的问题,最早的一个解决方案是由 Lea Verou 提供的一个 -prefix-free 脚本。你只需要在你的 .html
文件中插入一个 prefixfree.js
文件(可以是文档任何地方),建议把这个脚本文件放在样式表之后。
添加这个脚本之后,使用CSS3的属性时,只需书写标准样式即可。但是这种做法将所有压力交给了客户端来处理。如此一来页面解析压力就大了,性能会打一定的折扣,并且一旦脚本加载失败,那么就会出现浏览器无法正常渲染CSS3的样式风格。
prefixfree脚本仅在IE9+、Opera10+、Firefox3.5+、Safari4+得到支持。
除了prefixfree脚本之外,很多同学依赖于文本编辑器的插件来处理。这里来看看Sublime Text编辑器里是如何实现Autoprefixer功能的。
要在编辑器中安装 Autoprefixer 插件,首先需要你的环境中已经安装好了 Node.js 。你可以在命令终端执行:
node -v
来检测是否已安装,如果没有安装,请先安装。在这里假设你已具备Node.js环境。
现在开启你的Sublime Text编辑器,你可以同时按下 command + Shift + p
三个键,选择"Install Package"。然后搜索 Autoprefixer 。
现在你在你的Sublime Text中使用Autoprefixer功能。假设你在样式文件中输入:
.box { transform: rotate(45deg); border-radius: 5px; box-shadow: 1px 1px 0 rgba(0,0,0,.25); transition: all .2s ease .1s; }
这个时候你只需要同时按下 Command + Shift + P
三个键,选择“Autoprefix CSS”,并且回车,就能得到下面这样的代码:
.box { -webkit-transform: rotate(45deg); transform: rotate(45deg); border-radius: 5px; box-shadow: 1px 1px 0 rgba(0,0,0,.25); transition: all .2s ease .1s; }
如下图所示:
注:不同的配置,执行的效果不一样。详细可以点击 这里 查阅。
随着CSS预处理器越来越普及,部分同学开始采用预处理器中的混合宏来处理CSS3前缀的事项。比如说 Compass ,里面就是使用Sass的mixin为CSS3需要带前缀的属性定制了一些mixin。还有类似于Stylus中的 nib 等。预处理器中的混合宏确实可以解决很多问题,但也产生了新的问题,就是它所使用的语法是全新的,如果要使用就必须重新学习,另外这类工具的演进速度通常都会跟不上浏览器的发展速度,这样也会造成其产生的CSS有过时的问题,有时候为了解决一些问题,还需要自己去写 mixins 。比如:
正如前面所说的,如果要跟上浏览器的演进,就需要不断的更新你的CSS3 mixins,不然就会造成你的代码不是最新的。其中Compass就存在这样的问题:
@import "compass"; .box { @include border-radius(5px); }
编译出来的CSS:
.box { -moz-border-radius: 5px; -webkit-border-radius: 5px; border-radius: 5px; }
而现实却不尽人意,因为到写这篇文章为止,我们写圆角属性只需要:
.box { border-radius: 5px; }
各主流浏览器就能正常的解析。造成这个原因的时,Compass中的CSS3的mixin没有跟上步子去更新定义好的mixins。
使用Sass、LESS、Stylus或者其他类似的工具都是属于CSS的前处理器(Preprocessor),而Autoprefixer则是一种后处理器(Postprocessor)。它是直接针对CSS本身来进行处理,不需要任何额外的语法。因为它是在CSS代码产生之后才进行后续处理。
Autoprefixer是以 Rework 这种架构所发展的CSS后处理器,他是将CSS代码解析后转成JavaScript的资料结构,进行处理后再产生新的CSS代码。
Autoprefixer会分析CSS代码,并且根据 Can I Use 所提供的资料来决定要加上哪些浏览器前缀,而你要做的事情就是把他加入自己的自动化开发工具中(比如 Grunt 或者 Gulp ),然后就可以直接使用W3C的标准来写CSS,不需要加上任何浏览器的私有前缀。
接下来看看如何使用自动化工具实现Autoprefixer功能。
假设你的环境中已具备了Grunt的运行环境,如果没有请先移步 Grunt官网 了解,这里不做过多阐述。
在Github中有一个 grunt-autoprefixer 的插件,按照其官方提示,我在命令行中执行了下面的语句:
npm install grunt-autoprefixer --save-dev
命令终端提示:
似乎没有成功(其实我也不太懂Grunt,只是临阵磨枪)。于是我改投@一丝姐姐说的 postcss 。在命令终端重新输入:
npm install grunt-postcss --save-dev
这下似乎有戏了:
不过我还跟着官网所说的执行了另外一个命令:
npm install grunt-postcss autoprefixer-core csswring
运行命令后可以看到下图的提示信息:
接下来需要在你项目的根目录中配置 Gruntfile.js
文件:
'use strict'; module.exports = function(grunt) { // Dynamically loads all required grunt tasks require('matchdep').filterDev('grunt-*').forEach(grunt.loadNpmTasks); var autoprefixer = require('autoprefixer-core'); // Configures the tasks that can be run grunt.initConfig({ postcss: { options: { processors: [ autoprefixer({ browsers: ['last 2 version'] }).postcss ] }, // dist: { // src: 'src/css/*.css', // dest:'dest/css/*.css' // } multiple_files: { expand: true, flatten: true, src: 'src/css/*.css', // -> src/css/file1.css, src/css/file2.css dest: 'dest/css/' // -> dest/css/file1.css, dest/css/file2.css }, }, }); grunt.loadNpmTasks('grunt-postcss'); grunt.registerTask('default', ['postcss']); };
为了验证这样做是否正确,我在项目中的 src/css/
中创建了一个 main.css
文件,然后输入代码:
a { transition: all .2s ease .1s; transform: rotate(45deg) translateY(200px); }
在命令终端执行:
grunt
终端将运行:
Running "postcss:multiple_files" (postcss) task File dest/css/main.css created. Done, without errors.
查看项目中自动创建了一个 dest/css/main.css
文件,而里面的代码:
a { transition: all .2s ease .1s; -webkit-transform: rotate(45deg) translateY(200px); transform: rotate(45deg) translateY(200px); }
正是我需要的样式代码。这样尝试一回,觉得比使用Sass中的mixin爽多了。
除了Grunt可以配置Autoprefixer之外,还可以使用Gulp来配置。这里也假设你的项目中已具备了Gulp的运行环境,如果没有,可以查阅 Gulp官网 相关资料。
根据 gulp-autoprefixer 官网提示,我在命令终端输入了:
npm install gulp-autoprefixer --save-dev
在终端中可以看到这样的提示信息:
在Grunt中需要在 Gruntfile.js
进行配置,而在Gulp中也有点类似,需要在 gulpfile.js
中进行配置:
// include gulp var gulp = require('gulp'); // include plug-ins var autoprefix = require('gulp-autoprefixer'); // JS hint task gulp.task('styles', function() { gulp.src(['./src/styles/*.css']) .pipe(autoprefix('last 2 versions')) .pipe(gulp.dest('./build/styles')); });
看上去要比 Gruntfile.js
配置简单一些。为了验证操作是否正确,我在项目中创建了 src/styles/style.css
,并且在 style.css
文件中输入了:
a { transform: translateY(20px) rotate(45deg); }
接下来在命令终端执行:
gulp styles
看到如下提示信息:
[12:53:26] Using gulpfile ~/Sites/test/gulp-autoprefixer/gulpfile.js [12:53:26] Starting 'styles'... [12:53:26] Finished 'styles' after 7.26 ms
此时,在项目中会自动创建一个 build/styles/style.css
文件,打开这个文件查看代码:
a { -webkit-transform: translateY(20px) rotate(45deg); -ms-transform: translateY(20px) rotate(45deg); transform: translateY(20px) rotate(45deg); }
正是我们需要的。
其实在 PostCSS 也提供了有关于如何在Gulp中配置Autoprefixer的说明。感兴趣的同学可以 看看 。
有了Autoprefixer这样的工具对于处理CSS3属性前缀来说就不再是头痛的事情了。当然,如果你正在使用CSS预处理器编写代码,那么也可以很完美的结合Autoprefixer去处理。
经过几年的技术演进,CSS3属性前缀的问题已不再是一个问题。如今天你完全可以忽略我要不要加前缀,要加哪些前缀,而只需要专心去码你的代码。把这些烦人的事情交给Autoprefixer去处理。当然,越到后面,或许我们都不需要使用任何前缀。
常用昵称“大漠”,W3CPlus, Sass中国 创始人,目前就职于Ctrip UED。中国Drupal社区核心成员之一。对HTML5、CSS3和Sass等前端脚本语言有非常深入的认识和丰富的实践经验,尤其专注对CSS3的研究,是国内最早研究和使用CSS3技术的一批人。CSS3、Sass和Drupal中国布道者。2014年出版《 图解CSS3:核心技术与案例实战 》。