easy-animation | Animation for Sass

最近由於項目緣故,勾搭上了Sasscss

其實在折騰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。雖然這樣的代碼不會出現任何異常,但做爲一個稍稍有點潔癖的程序員,估計都沒法忍受這樣的效果。

隨後想了幾個解決方法,都不能很好的解決。主要被如下幾個問題困擾着:

  1. @keyframes所配置的屬性,有可能帶瀏覽器的prefix(-webkit-transform),也有可能不帶(opacity )。
  2. 如何才能對不一樣prefix的@keyframes輸出對應的屬性。如@-webkit-keyframes能對應上-webkit-transform,而opacity這類非私有的屬性則不帶上prefix。
  3. 每個@keyframes對應的配置屬性,都是經過@content來傳值的。翻查了一下Sass的文檔,也沒看到哪裏有說起到訪問@content的方式。

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

 

參考資料:

http://bourbon.io/

http://sass-lang.com/

http://compass-style.org/

相關文章
相關標籤/搜索