110
92

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Web Animations API を使ってみる

Last updated at Posted at 2018-01-23

Animation周りが苦手だったので、Flash のタイムラインアニメーションエディタみたいなものを練習がてら作ってみたい、ということで勉強した。

本記事は勉強ログ気味。

Web Animations API とは

CSS Animation の keyframe 制御を JS から可能にしたようなもの。
CSS Animation は 自分で止まったり再開したりできないし、フレーム制御も出来ない。 JS から制御できないのでコントロールしづらかったが、その問題を解決する。

Web Animations 実装具合と Polyfill

Can I Use 見る限りは Firefox で 実装済み、 Chrome で実装中
https://caniuse.com/#feat=web-animation

polyfill なしで試した結果、chrome で elem.animate(...) は動くけど、 elem.getAnimations()document.timeline が存在しない感じだった。

実際は polyfill 使うことになると思う。

簡単な使い方

polyfill を npm から適用

import 'web-animations-js/web-animations-next.min.js'

使う

const el = document.querySelector('.my-selector')
el.animate([{opacity: 0}, {opacity: 1}], 1000)

1000ms かけてopacity: 0 から 1 まで遷移。デフォルトだとリピート無し。

無限リピート

const el = document.querySelector('.my-selector')
el.animate([{opacity: 0}, {opacity: 1}], {
  duration: 1000,
  iterations: Infinity
})

iterations で指定した回数繰り返す。

W3C の Spec 見る限りは次のコードも動くはずだが、 ポリフィルを使う限りは動かなかった。

const el = document.querySelector('.my-selector')
el.animate({opacity: 0}, 1000)

Stop & Go

const animation = el.animate([{opacity: 0}, {opacity: 1}], 1000)
animation.pause()
animation.play()

あるエレメントに適用されている全ての animation を操作する。

el.getAnimations().forEach(a => a.pause())
el.getAnimations().forEach(a => a.play())

ドキュメント内の全てのアニメーションを取得する。

const anims = document.timeline.getAnimations()

keyframe の offset 制御

el.animate(
  [
    {opacity: 0, offset: 0},
    {opacity: 0.5, offset: 0.8},
    {opacity: 1, offset: 1}
  ],
  2000
)

0 から 始まり、 1 で終わる。 (0と1は省略可能)
この例では 2000 * 0.8 = 1600 ms かけて opacity: 0.5 になり、残り 400ms で 1になる。

easing 制御

el.animate(
  [
    {opacity: 0, offset: 0},
    {opacity: 0.5, offset: 0.8, easing: 'ease-in-out'},
    {opacity: 1, offset: 1}
  ],
  2000
)

何も指定しない場合、 デフォルトの easing は linear。 ここで指定できるのは timing-function の文字列

CSS timing function

ある時間中に 0 から 1 まで値が変化(transisiton)する時、それがどのような変化を描くかの関数、を示す css 上での表現
組み込みの timinig-function は linear, ease, ease-in, ease-out, ease-in-out。

それらは 3次ベジェ曲線 cubic-bezier(x1, y1, x2, y2) で表現可能。

離散的ではない値の表現には steps, steps-start, step-end を使う。

React で使う

自分ならこういう風に表現するかなぁという実装

import 'web-animations-js/web-animations-next.min.js'
import React from 'react'
import ReactDOM from 'react-dom'

class Animation extends React.Component {
  componentDidMount() {
    const el = ReactDOM.findDOMNode(this)
    const { timelines } = this.props
    for (const tl of timelines) {
      const { keyframes, ...others } = tl
      el.animate(tl.keyframes, others)
    }
  }

  render() {
    return this.props.children
  }
}

export default () => {
  return (
    <Animation
      timelines={[
        {
          keyframes: [{ opacity: 1 }, { opacity: 0.5 }, { opacity: 1 }],
          duration: 1000,
          iterations: Infinity
        },
        {
          keyframes: [
            { background: 'white', offset: 0 },
            { background: 'red', offset: 0.9 },
            { background: 'white', offset: 1 }
          ],
          duration: 3000,
          spacing: 'spaced(left)'
        }
      ]}
    >
      <span>Hello</span>
    </Animation>
  )
}

不満

組み込みの easing 関数の任意フレームでの値を JS から知る方法がない。 getComputedProperty() を使うしかない。

次に調べること

普通に使うだけならこれだけで一通りなんでも出来る。
タイムラインアニメーションエディタを作る場合、要はこの keyframes の JSON を生成できれば良い。
任意の実行フレームに巻き戻したり、とかやるとややこしくなってくる。それはこれから調べる。

実行効率のために composition に関する部分をちゃんと読まないといけなさそう。

参考

これを上から下まで全部読むだけ

110
92
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
110
92

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?