最近由於項目緣故,勾搭上了Sass。css
其實在折騰Sass以前,也有簡單用過一下Less。但礙於Less提供的一些API實在讓人以爲有點多餘,用着就是不順手,最後就不了了之啦。html
Sass之因此用起來舒服和順手,很大程度上是由於Compass的存在。Compass提供的足夠豐富的API,簡直讓你以爲寫CSS是一種享受。css3
不過...程序員
Compass竟然不支持animation!對,沒錯,就是CSS3那個作來作動畫的animation!(至少我翻了很久的Compass文檔也沒找到...)web
或許你會吐槽說:「嘖,本身用Sass的@mixin封裝一個animation的方法就搞定啦!」瀏覽器
恩,我一開始也是這麼想的,而後我也這麼作了...sass
———— 正文分割線 ————less
做爲一個Sass新手,我想要一個animation的@mixin時,必然是:工具
/* animation.scss */ @mixin animation($duration, $name, $count, $function) { -webkit-animation-duration: $duration; -webkit-animation-name: $name; -webkit-animation-iteration-count: $count; -webkit-animation-timing-function: $function; -moz-animation-duration: $duration; -moz-animation-name: $name; -moz-animation-iteration-count: $count; -moz-animation-timing-function: $function; -ms-animation-duration: $duration; -ms-animation-name: $name; -ms-animation-iteration-count: $count; -ms-animation-timing-function: $function; -o-animation-duration: $duration; -o-animation-name: $name; -o-animation-iteration-count: $count; -o-animation-timing-function: $function; animation-duration: $duration; animation-name: $name; animation-iteration-count: $count; animation-timing-function: $function; }
恩,這樣貌似就達到了用Sass實現了animation的目的啦。優化
而後咱們再優化一下代碼:
/* animation.scss */ @mixin animation($name, $duration, $function: ease, $delay: 0s, $count: infinite) { -webkit-animation: $name $duration $function $delay $count; -moz-animation: $name $duration $function $delay $count; -ms-animation: $name $duration $function $delay $count; -o-animation: $name $duration $function $delay $count; animation: $name $duration $function $delay $count; }
這樣看,代碼優雅多了(自我感受良好~)。
文章這樣就結束了?坑爹嗎?!
固然不是!想用animation作動畫,天然還要把@keyframes也用上。按照上面的思路,繼續用@mixin封裝一下相關css代碼:
/* keyframes.scss */ @mixin keyframes($animationName) { @-webkit-keyframes $animationName { @content; } @-moz-keyframes $animationName { @content; } @-ms-keyframes $animationName { @content; } @-o-keyframes $animationName { @content; } @keyframes $animationName { @content; } }
看起來貌似一切都妥妥的。
配合上Compass愉快的投入生產:
/* demo1.scss */ @import "compass"; @import "animation.scss"; @import "keyframes.scss"; .circle { @include animation(circle, 1s, linear); } @include keyframes(circle) { 0% { opacity: 0; @include translate(100px, 0); } 100% { opacity: 1; @include translate(0, 0); } }
這樣寫Sass,真的很簡潔很舒服。忍不住打開編譯生成的css文件一看,差點哭了出來:
/* demo1.css */ .circle { -webkit-animation: circle 1s linear 0s infinite; -moz-animation: circle 1s linear 0s infinite; -ms-animation: circle 1s linear 0s infinite; -o-animation: circle 1s linear 0s infinite; animation: circle 1s linear 0s infinite; } @-webkit-keyframes circle { 0% { opacity: 0; -webkit-transform: translate(100px, 0); -moz-transform: translate(100px, 0); -ms-transform: translate(100px, 0); -o-transform: translate(100px, 0); transform: translate(100px, 0); } 100% { opacity: 1; -webkit-transform: translate(0, 0); -moz-transform: translate(0, 0); -ms-transform: translate(0, 0); -o-transform: translate(0, 0); transform: translate(0, 0); } } @-moz-keyframes circle { 0% { opacity: 0; -webkit-transform: translate(100px, 0); -moz-transform: translate(100px, 0); -ms-transform: translate(100px, 0); -o-transform: translate(100px, 0); transform: translate(100px, 0); } 100% { opacity: 1; -webkit-transform: translate(0, 0); -moz-transform: translate(0, 0); -ms-transform: translate(0, 0); -o-transform: translate(0, 0); transform: translate(0, 0); } } @-ms-keyframes circle { 0% { opacity: 0; -webkit-transform: translate(100px, 0); -moz-transform: translate(100px, 0); -ms-transform: translate(100px, 0); -o-transform: translate(100px, 0); transform: translate(100px, 0); } 100% { opacity: 1; -webkit-transform: translate(0, 0); -moz-transform: translate(0, 0); -ms-transform: translate(0, 0); -o-transform: translate(0, 0); transform: translate(0, 0); } } @-o-keyframes circle { 0% { opacity: 0; -webkit-transform: translate(100px, 0); -moz-transform: translate(100px, 0); -ms-transform: translate(100px, 0); -o-transform: translate(100px, 0); transform: translate(100px, 0); } 100% { opacity: 1; -webkit-transform: translate(0, 0); -moz-transform: translate(0, 0); -ms-transform: translate(0, 0); -o-transform: translate(0, 0); transform: translate(0, 0); } } @keyframes circle { 0% { opacity: 0; -webkit-transform: translate(100px, 0); -moz-transform: translate(100px, 0); -ms-transform: translate(100px, 0); -o-transform: translate(100px, 0); transform: translate(100px, 0); } 100% { opacity: 1; -webkit-transform: translate(0, 0); -moz-transform: translate(0, 0); -ms-transform: translate(0, 0); -o-transform: translate(0, 0); transform: translate(0, 0); } }
能夠看到,每個@keyframes裏面,都重複輸出了一套完整兼容的transform。雖然這樣的代碼不會出現任何異常,但做爲一個稍稍有點潔癖的程序員,估計都沒法忍受這樣的效果。
隨後想了幾個解決方法,都不能很好的解決。主要被如下幾個問題困擾着:
Google了一下相關信息,也沒找到現成的animation for sass的方法。
幸好最後在stackoverflow上發現了一個有趣的問題→_→傳送門。
提問人和我遇到了相似的狀況,也是卡在了@keyframes的私有屬性輸出的問題。十分幸運的是,在問題下面的回答中,發現了Bourbon這個Sass的庫。
Bourbon所封裝的@keyframes方法,就很好的解決了我上面遇到的問題。
忍不住看了一下它的源碼,實現思路很妙。還幫助我更好的弄清了Compass中experimental的實現思路。
考慮到Compass和Bourbon沒有相互依賴的關係,同時使用會出現變量污染的問題。最後根據Bourbon的實現思路,重構了這麼一個叫作 easy-animation 的動畫工具集。
/* easy-animation.scss */ // easy-animation // Author: Maple Jan // Date: 2014-04-11 // Support browser's private prefix. $ea-prefix-for-webkit: true !default; $ea-prefix-for-mozilla: true !default; $ea-prefix-for-microsoft: true !default; $ea-prefix-for-opera: true !default; $ea-prefix-for-spec: true !default; // required for keyframe mixin // Disable all browser's private prefix. @mixin ea-disable-prefix-for-all() { $ea-prefix-for-webkit: false; $ea-prefix-for-mozilla: false; $ea-prefix-for-microsoft: false; $ea-prefix-for-opera: false; $ea-prefix-for-spec: false; } // Example usage: // @include ea-transition(all 2s ease 0s); @mixin ea-transition($value, $prefixs: webkit moz ms o spec) { @each $prefix in $prefixs { @if $prefix == webkit { @if $ea-prefix-for-webkit { -webkit-transition: $value; } } @else if $prefix == moz { @if $ea-prefix-for-mozilla { -moz-transition: $value; } } @else if $prefix == ms { @if $ea-prefix-for-microsoft { -ms-transition: $value; } } @else if $prefix == o { @if $ea-prefix-for-opera { -o-transition: $value; } } @else if $prefix == spec { @if $ea-prefix-for-spec { transition: $value; } } @else { @warn "Unrecognized prefix: #{$prefix}"; } } } // Example usage: // @include ea-transform(scale(1)); @mixin ea-transform($value, $prefixs: webkit moz ms o spec) { @each $prefix in $prefixs { @if $prefix == webkit { @if $ea-prefix-for-webkit { -webkit-transform: $value; } } @else if $prefix == moz { @if $ea-prefix-for-mozilla { -moz-transform: $value; } } @else if $prefix == ms { @if $ea-prefix-for-microsoft { -ms-transform: $value; } } @else if $prefix == o { @if $ea-prefix-for-opera { -o-transform: $value; } } @else if $prefix == spec { @if $ea-prefix-for-spec { transform: $value; } } @else { @warn "Unrecognized prefix: #{$prefix}"; } } } // Example usage: // @include ea-animation(wrap_s0_p1, 2s, ease, 0s, infinite); @mixin ea-animation($name, $duration, $function: ease, $delay: 0s, $count: infinite) { -webkit-animation: $name $duration $function $delay $count; -moz-animation: $name $duration $function $delay $count; -ms-animation: $name $duration $function $delay $count; -o-animation: $name $duration $function $delay $count; animation: $name $duration $function $delay $count; } // Example usage: // @include ea-keyframes(wrap_s0_p1) { // 0% { // opacity: 1; // @include ea-transform(scale(1)); // } // 50% { // opacity: 0.8; // @include ea-transform(scale(0.8)); // } // 100% { // opacity: 1; // @include ea-transform(scale(1)); // } // } @mixin ea-keyframes($name) { $_ea-prefix-for-webkit: $ea-prefix-for-webkit; $_ea-prefix-for-mozilla: $ea-prefix-for-mozilla; $_ea-prefix-for-microsoft: $ea-prefix-for-microsoft; $_ea-prefix-for-opera: $ea-prefix-for-opera; $_ea-prefix-for-spec: $ea-prefix-for-spec; @if $_ea-prefix-for-webkit { @include ea-disable-prefix-for-all(); $ea-prefix-for-webkit: true; @-webkit-keyframes #{$name} { @content; } } @if $_ea-prefix-for-mozilla { @include ea-disable-prefix-for-all(); $ea-prefix-for-mozilla: true; @-moz-keyframes #{$name} { @content; } } @if $_ea-prefix-for-microsoft { @include ea-disable-prefix-for-all(); $ea-prefix-for-microsoft: true; @-ms-keyframes #{$name} { @content; } } @if $_ea-prefix-for-opera { @include ea-disable-prefix-for-all(); $ea-prefix-for-opera: true; @-o-keyframes #{$name} { @content; } } @if $_ea-prefix-for-spec { @include ea-disable-prefix-for-all(); $ea-prefix-for-spec: true; @keyframes #{$name} { @content; } } $ea-prefix-for-webkit: $_ea-prefix-for-webkit; $ea-prefix-for-mozilla: $_ea-prefix-for-mozilla; $ea-prefix-for-microsoft: $_ea-prefix-for-microsoft; $ea-prefix-for-opera: $_ea-prefix-for-opera; $ea-prefix-for-spec: $_ea-prefix-for-spec; }
十分簡潔優雅的使用:
/* demo2.scss */ @import "easy-animation.scss"; .pen { @include ea-animation(pen, 1s, linear); } @include ea-keyframes(pen) { 0% { opacity: 0; @include ea-transform(translate(100px, 0)); } 100% { opacity: 1; @include ea-transform(translate(0, 0)); } }
生成的CSS:
/* demo2.css */ .pen { -webkit-animation: pen 1s linear 0s infinite; -moz-animation: pen 1s linear 0s infinite; -ms-animation: pen 1s linear 0s infinite; -o-animation: pen 1s linear 0s infinite; animation: pen 1s linear 0s infinite; } @-webkit-keyframes pen { 0% { opacity: 0; -webkit-transform: translate(100px, 0); } 100% { opacity: 1; -webkit-transform: translate(0, 0); } } @-moz-keyframes pen { 0% { opacity: 0; -moz-transform: translate(100px, 0); } 100% { opacity: 1; -moz-transform: translate(0, 0); } } @-ms-keyframes pen { 0% { opacity: 0; -ms-transform: translate(100px, 0); } 100% { opacity: 1; -ms-transform: translate(0, 0); } } @-o-keyframes pen { 0% { opacity: 0; -o-transform: translate(100px, 0); } 100% { opacity: 1; -o-transform: translate(0, 0); } } @keyframes pen { 0% { opacity: 0; transform: translate(100px, 0); } 100% { opacity: 1; transform: translate(0, 0); } }
以上.
本文連接:http://www.cnblogs.com/maplejan/p/3659830.html
本文做者:Maple Jan
參考資料: