WAAPI入门

发布于 大漠

动画在Web应用中不是必须的,但是使用得好能起到锦上添花的作用。早期在Web中看到的动画主要有Flash、Gif图片动画、JavaScript动画、SVG动画、APNG动画和CSS3动画等。特别是随着浏览器对CSS3属性支持力度的提高,使用CSS3制作动画的情景在Web应用中越来越频繁。

虽然实现动画的技术可以有多种不同的实现方式,但每种技术都存在一定的缺点,比如CSS3动画必须通过JavaScript去获取动态改变的值,setInterval的时间往往是不精确的而且还会卡顿,APNG动画体积过大等等。

实现方法多意味着实现方式也不同,其中涉及到的技术点也不同,对于Web开发者而言,都希望制作Web动画都具有一套统一的API规则:

WAAPI入门

值得庆幸的是,W3C提出Web Animation API,它致力于集合CSS3动画的性能,JavaScript的灵活,动画库的丰富等各家所长,将尽可能多的动画控制由原生浏览器实现,并添加许多CSS不具备的变量、控制以及调试选项等。

WAAPI入门

那么从这篇文章开始,我们将会花几节课的时间和大家一起来探讨Web Animation API相关的知识。

CSS3 Animation

W3C提出的Web Animation API常简称为WAAPI。在开始介绍WAAPI之前,咱们先来回忆一下现在制作动画常用的方法CSS3 Animation。为什么要拿CSS3 Animation出来说呢?因为CSS3 Animation的特性和WAAPI中很多特性非常的类似。

CSS3 Animation中动画最关键的是需要先通过@keyframes来声明一个动画,然后通过animation-name来调用@keyframes声明的动画。不然动画声明、调用之后,还需要触发动画。而触发动画方式主要有文档载入、状态伪类、JavaScript事件等方式来触发。

除此之外,CSS3 Animation除了animation-name之外,还提供了其它属性来控制动画,比如:

  • animation-duration动画持续播放时长
  • animation-delay动画延迟播放的时长
  • animation-directoin动画播放方向
  • animation-timing-function动画播放函数功能
  • animation-fill-mode动画停留状态
  • animation-iteration-count动画播放次数
  • animation-play-state动画播放状态

简单来看W3C官网提供的一张有关于CSS3 Animation属性变化的过程示意图:

CSS3 Animation

我们在这里对CSS3 Animation相关的介绍不做过多的阐述,如果您从未接触过有关于CSS3 Animation相关的知识,建议您先看看这篇文章

为了后面更好的介绍WAAPI,咱们先来简单的看一个CSS3 Animation动画效果。

@keyframes anime {
  0% {
    transform: none;
  }

  25% {
    transform: translate(200px, 0);
  }

  50% {
    transform: translate(200px, 200px);
  }

  75% {
    transform: translate(0, 200px);
  }

  100% {
    transform: none;
  }
}

然后在需要有动效的元素上调用声明好的动画:

animation: anime 1000ms cubic-bezier(.6, 0, 1, .6) 500ms 50 normal both running;

上面看到的就是通过CSS3 Animation实现的一个简单的动画效果。当然,使用CSS3 Animation还可以实现很多复杂的动效

前面也说到过,每种实现Web动画技术都存在自己的缺陷,CSS3 Animation也不例外。至于不足之处,这里不多说。有关于CSS3 Animation制作动画先说到这里,咱们来看看WAAPI怎么来实现上面的的动效。

WAAPI入门

在CSS3 Animation和Transition特性还没出来之前,在Web页面中实现一些简单的动效,大家用得比较多的应该是jQuery的.animate()或者JavaScript中的setTimeoutsetInterval来实现一些动效

同样的,在WAAPI中,其核心也是提供了类似于jQuery中的.animate()一样的一个API:

element.animate(effect, options);

其中element是指需要有动效的元素,比如上例中的.anime元素,effect是一个KeyframeEffects数组,对应的也就是CSS3 Animation中的@keyframs anime,另外options是一个AnimationEffectTimingProperties参数,对应的是animation-*属性。

AnimationEffectTimingProperties对应的animation-*

AnimationEffectTimingProperties animation-* 描述
AnimationEffectTimingProperties.delay animation-delay 动画延迟播放的时长
AnimationEffectTimingProperties.direction animation-directoin 动画播放方向
AnimationEffectTimingProperties.duration animation-duration 动画持续播放时长
AnimationEffectTimingProperties.easing animation-timing-function 动画播放函数功能
AnimationEffectTimingProperties.fill animation-fill-mode 动画停留状态
AnimationEffectTimingProperties.iterations animation-iteration-count 动画播放次数

除此之外,WAAPI还提供了AnimationEffectTimingProperties.iterationStartAnimationEffectTimingProperties.endDelay等API。至于这些API怎么使用,先别急。接下来,我们要做的是怎么使用WAAPI来实现上面CSS3 Animation实现的动画效果。

假设我们需要附上动效的元素是

<div class="anime"></div>

根据前面介绍的,需要先选中这个元素,在JavaScript中,可以使用document.querySelector():

var eleAnime =document.querySelector('.anime')

选中元素,再调用WAAPI的核心API:

eleAnime.animate(effect, options);

现在关键之处,怎么将effectoptions调入进去。回忆一下,前面说到过,effect是一个KeyframeEffects数组,而options是一个对象:

eleAnime.animate(
    // 对应的是@keyframes
    [
        {...},
        {...}
    ],
    //对应的是animation-*
    {
        ...
    }
)

可能有同学会好奇,怎么将CSS Animation中的@keyframes对应的转换过来,其实很简单,KeyframeEffects是一个数组,数组里面有多个对象,这里面的每个对象就是对应@keyframes中的每个帧。这样一来,可以变成:

eleAnime.animate(
    // 对应的是@keyframes
    [
        {
              transform: 'none'
        },
        {
              transform: 'translate(200px, 0)'
        },
        {
              transform: 'translate(200px, 200px)'
        },
        {
              transform: 'translate(0, 200px)'
        },
        {
              transform: 'none'
        }
    ],
    //对应的是animation-*
    {
        ...
    }
)

问题来了,在CSS3 Animation中可以通过类似0%这样表示对应的帧,那么在WAAPI中如何表达呢?这里需要特别出来,如果在WAAPI中没有显式的设置对应的帧率,那么会将其平均分配。为了能达到更好的效果,WAAPI中提供了一个offset属性,其值对应的是0~1,也就对应@keyframes中的0%~100%。这样一来,上面的的@keyframes在WAAPI对应的是:

eleAnime.animate(
    // 对应的是@keyframes
    [
        {
            offset: 0,
              transform: 'none'
        },
        {
            offset: 0.25,
              transform: 'translate(200px, 0)'
        },
        {
            offset: 0.5,
              transform: 'translate(200px, 200px)'
        },
        {
            offset: 0.75,
              transform: 'translate(0, 200px)'
        },
        {
            offset: 1,
              transform: 'none'
        }
    ],
    //对应的是animation-*
    {
        ...
    }
)

现在完成一半了,还需要添加options,其实这一步也非常简单:

eleAnime.animate(
    // 对应的是@keyframes
    [
        {
            offset: 0,
              transform: 'none'
        },
        {
            offset: 0.25,
              transform: 'translate(200px, 0)'
        },
        {
            offset: 0.5,
              transform: 'translate(200px, 200px)'
        },
        {
            offset: 0.75,
              transform: 'translate(0, 200px)'
        },
        {
            offset: 1,
              transform: 'none'
        }
    ],
    //对应的是animation-*
    {
        delay: 500,
        endDelay: 0,
        fill: 'both',
        iterationStart: 0,
        iterations: 50,
        duration: 1000,
        direction: 'normal',
        easing: 'cubic-bezier(.6, 0, 1, .6)'
    }
)

对应的效果如下:

为了方便管理,可以将代码做一上优化:

var eleAnime = document.querySelector('.anime');
var animeKeyframes = [
    {
        offset: 0,
          transform: 'none'
    },
    {
      	offset: 0.25,
          transform: 'translate(200px, 0)'
    },
    {
        offset: 0.5,
          transform: 'translate(200px, 200px)'
    },
    {
        offset: 0.75,
          transform: 'translate(0, 200px)'
    },
    {
        offset: 1,
          transform: 'none'
    }
];
var animeOptions = {
      delay: 500,
    endDelay: 0,
    fill: 'both',
    iterationStart: 0,
    iterations: 50,
    duration: 1000,
    direction: 'normal',
    easing: 'cubic-bezier(.6, 0, 1, .6)'
};
eleAnime.animate(animeKeyframes,animeOptions);

除了使用上面的方法之外,在WAAPI中还有另一种方式:

new Animation(effect, timeline)

这种方法和前面的略有不同,要让动画生效,需要配合WAAPI中的new keyframeEffect(element, keyframeSet, keyframeOptions).play()方法。这样一来,上面的示例可以改成:

var eleAnime = document.querySelector('.anime');
var animeKeyframes = {
  	transform: ['none', 'translate(200px, 0)', 'translate(200px, 200px)', 'translate(0, 200px)', 'none']
};
var animeOptions = {
    delay: 500,
    endDelay: 0,
    fill: 'both',
    iterationStart: 0,
    iterations: 50,
    duration: 1000,
    direction: 'normal',
    easing: 'cubic-bezier(.6, 0, 1, .6)'
};
var effect = new KeyframeEffect(eleAnime, animeKeyframes, animeOptions);
var animation = new Animation(effect, eleAnime.ownerDocument.timeline);
animation.play();

效果如下:

特别提示,使用这种方式,目前支持的浏览器较少,要想在浏览器看到有效果,需要引入一个polyfill

<script src="https://cdnjs.cloudflare.com/ajax/libs/web-animations/2.2.1/web-animations-next.min.js"></script>

效果看到,我们来看下面的效果,是CSS Animation和WAAPI实现的效果:

总结

文章主要介绍了WAAPI入门相关的知识点,通过WAAPI两种不同方式来实现动效。上面涉及到的只是WAAPI上的皮毛知识点,主要让大家通过简单的实例对WAAPI有一个初步的认识,以及对比其实现动效和CSS3有何不同之处和相似之处。后面我们将继续深入的学习有关于WAAPI相关的其他知识点,因为这套原生的动画API能帮我实现更好的动效。

虽然现在浏览器对WAAPI的支持力度还不是很强,但我们应该深信,随着时间的推移,一定会得到完美的支持。尽管还未得到很好的支持,但并不影响我们对WAAPI的学习。如果您对这方面的知识感兴趣的话,欢迎加入我们,如果你有相关的经验,欢迎在评论中与我们一起分享。

大漠

常用昵称“大漠”,W3CPlus创始人,目前就职于手淘。中国Drupal社区核心成员之一。对HTML5、CSS3和Sass等前端脚本语言有非常深入的认识和丰富的实践经验,尤其专注对CSS3的研究,是国内最早研究和使用CSS3技术的一批人。CSS3、Sass和Drupal中国布道者。2014年出版《图解CSS3:核心技术与案例实战》。

如需转载,烦请注明出处:https://www.fedev.cn/animation/waapi-basic-intro.htmlAir Jordan VIII Low