Web Animations API

Web Animations APIはCSSアニメーションやCSSトランジションをJavaScript から操作するAPIです
*Safari 13.1のリリースからWeb Animations APIはIE以外のブラウザでサポートされています

目次
  1. 基本
  2. keyframes
  3. options
  4. 再生の制御
  5. 使用例

基本

keyframes :配列(キーフレームオブジェクトの配列)またはオブジェクト(プロパティ名がキー)
options :再生時間を表す整数値(ミリ秒単位)または タイミングプロパティを含むオブジェクト
例:{iterations: Infinity,duration: 3000} 3秒間のアニメーションを無限に

Element.animate(keyframes, options)
const box = document.getElementById("box")
box.animate(
[
  { transform: 'rotate(0)', opacity: 1 },// 0%のキーフレーム
  {opacity: 0}, // 50%のキーフレーム
  { transform: 'rotate(360deg)', opacity: 1 } // 100%のキーフレーム
]
{
  iterations: Infinity,
  duration: 5000
}
)

keyframes

*アニメーション可能なプロパティと値のセット(KeyframeEffect)

keyframesの2つの設定方法(配列オブジェクト)があります

//配列(オブジェクトの配列)
[
  { transform: 'rotate(0)', opacity: 1 },// 0%のキーフレーム
  {opacity: 0}, // 50%のキーフレーム
  { transform: 'rotate(360deg)', opacity: 1 } // 100%のキーフレーム
]

//オブジェクト(キーはCSSプロパティ・値は反復する値の配列)
{
  transform: [ 'rotate(0)', 'rotate(360deg)' ], //0%、100% の時の値
  opacity:[1, 0, 1]  // 0%、50%、100% の時の値
}

CSSのプロパティ名はキャメル ケースにします
例:background-color は backgroundColor

offset:0.0から1.0 までの数値またはnull
CSSの@keyframesでパーセンテージで指定するのと同じ
nullまたは指定されていない場合は隣接するキーフレーム間で等間隔になります

/*オブジェクトの配列
カンマで区切ったオフセットを直接指定できる
例では、色は10%で変化する*/
[
  { transform: 'rotate(0)', backgroundColor: '#ccc' },
  { backgroundColor: '#222', offset:0.1}, 
  { transform: 'rotate(360deg)', backgroundColor: '#ccc' } 
]

/*オブジェクト
指定された各オフセットが対応するキーフレームに適用されます
値が不十分な場合、オフセットが指定されていないキーフレームは等間隔になります*/
{
  transform: [ 'rotate(0)', 'rotate(360deg)' ], //0%、100% の時の値
  backgroundColor:['#ccc', '#222', '#ccc'], // 0%、10%、100% の時の値
  offset: [ 0, 0.1, 1]
}

easing
キーフレーム間に適用するイージングを指定できます
指定されたキーフレームから次のキーフレームまでのみ適用されます
*optionsで指定されたイージングは、アニメーションの全体に適用されます

linear*初期値 一定の速度
ちなみにCSSではeaseが初期値
ease開始と終了はゆっくり
ease-in最初はゆっくり
ease-out最初は速く
ease-in-outeaseより開始と終了はゆっくり
step-start開始時点で即変化
step-end終了時点で一気に変化する
steps(count, start|end)段階ごとに変化
cubic-bezier(x1,y1,x2,y2)ベジエ曲線にそって変化
//オブジェクトの配列
[
  { transform: 'rotate(0)', backgroundColor: '#ccc' },
  { backgroundColor: '#222', easing:'step-start'}, 
  { transform: 'rotate(360deg)', backgroundColor: '#ccc' } 
]

//オブジェクト
{
  transform: [ 'rotate(0)', 'rotate(360deg)' ], //0%、100% の時の値
  backgroundColor:['#ccc', '#222', '#ccc'], // 0%、10%、100% の時の値
  easing: ['linear','step-start','linear']
}

options

アニメーションの間隔時間のみを指定して1回だけの場合はミリ秒だけを指定できます

document.getElementById("box").animate(
[
  { transform: 'rotate(0)', backgroundColor: '#ccc' },
  { backgroundColor: '#222'}, 
  { transform: 'rotate(360deg)', backgroundColor: '#ccc' }
],5000)

タイミングプロパティのオブジェクト
ミリ秒単位です
*CSSのように秒指定(3s等)は使えません

duration反復が完了までにかかるミリ秒数
デフォルトは0(0だと実行されません)
delay開始を遅らせるミリ秒数
デフォルトは0
direction“normal”:通常
“reverse”:逆方向に実行
“alternate”:反復ごとに方向を切り替える
“alternate-reverse”:逆方向に実行し反復ごとに方向を切り替える
デフォルトは”normal”
easing上記参照
endDelayアニメーションの終了後に遅延するミリ秒数
デフォルトは0
fill“backwards”:アニメーションの効果を再生前に反映させる
“forwards”:アニメーションの効果を再生後も保持する
“both”:両方にするかを指定
デフォルトは”none”
iterationsアニメーションを繰り返す回数
デフォルトは1
Infinityは無限
iterationStart反復のどの時点でアニメーションを開始するか
デフォルトは 0.0
*2回反復するアニメーションで0.5にすると1回目の途中から3回目の途中で終了

再生の制御

メソッドの抜粋

pause()アニメーションの再生を一時停止します
play()アニメーションを開始または再開します
reverse()逆方向に再生されます
一時停止したアニメーションは逆方向に再開します
finish()アニメーションの最後までスキップ
cancel()再生を中止します
commitStyles()アニメーションされている要素にスタイルの終了状態を書き込みます
*アニメーションが削除された後でも適用される
<div id="box" style="width:100px; height:100px; background:#ccc; margin: 0 auto"></div>
<button id="play">play</button>
<button id="pause">pause</button>
<script>
const box = document.getElementById("box")
const play = document.getElementById("play")
const pause = document.getElementById("pause")
const animate = box4.animate(
[
  { transform: 'rotate(0)', backgroundColor: '#ccc' },
  { backgroundColor: '#222'}, 
  { transform: 'rotate(360deg)', backgroundColor: '#ccc' }
],5000)
animate.pause()
play.addEventListener('click',()=>animate1.play())
pause.addEventListener('click',()=>animate1.pause())
</script>

イベント
アニメーションの再生が終了したときの登録方法(3パターン)

addEventListener("finish", (event) => {
 //アニメーションが終了した時に実行する処理
 })

onfinish = (event) => { 
 //アニメーションが終了した時に実行する処理
}

finished.then(()=> {
  //アニメーションが終了した時に実行する処理
});
// 全てのアニメーションが終わるまで待つ
//getAnimationsの引数に{ subtree: true } を指定するとElementの子孫をターゲットとしたアニメーションも返します
const animations = Element.getAnimations();
const myAnimate = async () => {
  await Promise.all(animations.map((animation) => animation.finished));

}

getAnimations()でアニメーションの情報を取得できます
例:取得した情報からインスタンスのプロパティ(例はplaybackRate再生速度)を変更する

document.getAnimations().forEach(animation=>{
   animation.playbackRate *= .5;
   console.log(animation)
})

使用例

複数の要素に同じ又は一部異なるアニメーションを設定したい時はanimate()の配列を作ると便利です
*delayをズラす例

HELLO WORLD

<style>
.char{ 
 display: inline-block;
}
</style>
<p class="letters">HELLO WORLD</p>
<button id="start">start</button>
<script>
//JavaScriptで1文字ごとに<span>タグを追加
const el = document.querySelector('.letters');
const start = document.getElementById("start")
 const chars = el.innerHTML.trim().split("");
 el.innerHTML = chars.reduce((acc, char) => {
    char = char.replace(/\s+/, ' ');
    return `${acc}<span class="char">${char}</span>`;
  }, "");
//span要素を取得して配列に
const spans = document.querySelectorAll('.char');
const spansArray = Array.from(spans)
//animateの配列
const animations = spansArray.map((char, index) => {
  return char.animate(
    [
      {
        transform: `translateY(50px)`,
        opacity: 0
      },
      {
        transform: `translateY(0px)`,
        opacity: 1
      }
    ],
    {
      duration: 2000,
      easing: 'ease',
      fill: 'backwards',
      delay: 2000/chars.length * index+1
    }
  );
});
animations.forEach(animation=>{
  animation.pause()
})
//クリックした時
start.addEventListener('click', ()=>{
animations.forEach(animation=>{
  animation.finish()
  animation.play()
  })
})
</script>

CSSの@keyframesの値を動的に変更したい時

Web Animations APIを使用することなく
CSS変数を使いsetPropertyでstyle属性に値をセットできますが、Safariではなぜかセットした値がアニメーションに反映されませんでした😂
またrotate3dを使う時にSafariは一気に一回転するコードは動作しません

.box{
 --rotate3d: rotate3d(1,0,0,360deg);
 animation: rotate 10s;
}
@keyframes rotate {
 to{ /*これではSafariでは動作しない、動作するには%で数回に分ける必要が*/
   transform: var(--rotate3d);
  }
}
const box = document.querySelector('.box') 
box.style.setProperty('--rotate3d', 'rotate3d(0,1,0,360deg)')

そこでSafariにも対応して@keyframes(例ではtransform:rotate3d)を変更をするために
Web Animations APIでアニメーションしてsetKeyframes()でkeyframesの値として変更してみる
*キューブをクリックすると回転軸が変わります

4
3
2
5
6
1
 
const box = document.querySelector('#box') 
const anim = box.animate(
  {
   transform: [ 'rotate3d(0,1,0,0)', 'rotate3d(0,1,0,-120deg)' ,  'rotate3d(0,1,0,-240deg)', 'rotate3d(0,1,0,-360deg)' ], 
  },
 {
   iterations: Infinity,
   duration: 10000
 }
)
//要素をクリックしたら, 
 let x = true;
  box.addEventListener('click',()=>{
    let val = x ? '0,1,0': '1,0,0'
    x = !x  
    anim.effect.setKeyframes( {
     transform: [ `rotate3d(${val},0)`, `rotate3d(${val},-120deg)`, `rotate3d(${val},-240deg)`, `rotate3d(${val},-360deg)` ]
   })
 })