今天閑來無聊,重新來說說CSS3前綴的問題。在春節前和@一絲姐姐說起Sass中有關於gradient的mixins。姐姐說:
為什么還要用mixin呢?為什么不使用Autoprefixer?使用Autoprefixer,只需要輸入一行代碼,編譯器幫你做了一切,還糾結個毛mixin。
姐姐的一句話讓我汗顏,我還在思考着如何讓Sass來寫Gradient,或者類似這樣需要帶前綴的CSS3屬性。也這樣讓我在思考,那么有了 Autoprefixer這樣的后處理,Sass中有關於CSS3的mixins是不是已失去了他存在的意義。帶着這樣的為什么?我們一起來開啟今天有關 於CSS3前綴的探討。
CSS3的屬性為什么要帶前綴
使用過CSS3屬性的同學都知道,CSS3屬性都需要帶各瀏覽器的前綴,甚至到現在,依然還有很多屬性需要帶前綴。這是為什么呢?
我的理解是,瀏覽器廠商以前就一直在實施CSS3,但它還未成為真正的標准。為此,當一些CSS3樣式語法還存在波動時,它們提供針對瀏覽器的前綴。現在主要流行的瀏覽器內核主要有:
- Trident內核:主要代表為IE瀏覽器
- Gecko內核:主要代表為Firefox
- Presto內核:主要代表為Opera
- Webkit內核:產要代表為Chrome和Safari
而這些不同內核的瀏覽器,CSS3屬性(部分需要添加前綴的屬性)對應需要添加不同的前綴,也將其稱之為瀏覽器的私有前綴,添加上私有前綴之后的CSS3屬性可以說是對應瀏覽器的私有屬性:
- Trident內核:前綴為
-ms
- Gecko內核:前綴為
-moz
- Presto內核:前綴為
-o
- Webkit內核:前綴為
-webkit
來看一個簡單的示例,早期寫一個圓角border-radius
,需要這樣寫:
.box { -moz-border-radius: 5px; -webkit-border-radius: 5px; -o-border-radius: 5px; border-radius: 5px; }
這樣編寫代碼,無形之中給前端人員增加了不少工作量,於是開始有人在討論這個問題“如何在編寫CSS時不需要添加瀏覽器的私有前綴,又能讓瀏覽器識別?”
-prefix-free
為了解決手工書寫前綴的問題,最早的一個解決方案是由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。
使用Autoprefixer
使用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中配置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爽多了。
Gulp中配置Autoprefixer
除了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去處理。當然,越到后面,或許我們都不需要使用任何前綴。