easy-animation | Animation for Sass

最近因为项目缘故,勾搭上了Sass

其实在折腾Sass之前,也有简单用过一下Less。但碍于Less提供的一些API实在让人觉得有点多余,用着就是不顺手,最后就不了了之啦。

Sass之所以用起来舒服和顺手,很大程度上是因为Compass的存在。Compass提供的足够丰富的API,简直让你觉得写CSS是一种享受。

不过...

Compass居然不支持animation!对,没错,就是CSS3那个做来做动画的animation!(至少我翻了好久的Compass文档也没找到...)

或许你会吐槽说:“啧,自己用Sass的@mixin封装一个animation的方法就搞定啦!”

恩,我一开始也是这么想的,然后我也这么做了...

 

———— 正文分割线 ————

 

作为一个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/

 

 

posted @ 2014-04-12 00:21  Maple Jan  阅读(2417)  评论(0编辑  收藏  举报