anime.jsでスクロールに合わせたアニメーション

公開 :
最終更新 :

anime.jsはWebページにアニメーションを追加することができるシンプルな軽量JSライブラリで、使い方も簡単です。

anime.jsでスクロールアクションを行う方法を紹介します。

要素が画面に入った瞬間に一度だけアニメーション

「要素がブラウザの表示領域に入ったとき」はin viewという言葉で表現します。

in viewはライブラリも多数ありますが、簡単な計算でも実現できます。

document.addEventListener('scroll',function(){
    var windowHeight = window.innerHeight;
    var targetTop = document.getElementById('sample1').getBoundingClientRect().top;
    if(targetTop<windowHeight-100){
        anime({
            targets: '#sample1',
            translateX: 200,
            duration: 3000,
        });
        document.removeEventListener('scroll',arguments.callee);
    }
});

解説

window.innerHeightはブラウザの表示領域の高さです。似ている高さにdocument.documentElement.clientHeightというスクロールバー領域を除いた値を取得できるものがありますが、スクロールによってメニューが現れたり消えたりするブラウザでは挙動が不安定になります。

element.getBoundingClientRect().topはブラウザの表示領域左上を(0,0)とする、その要素の上端の位置を示します。element.getBoundingClientRect().top`はブラウザの表示領域左上を(0,0)とする、その要素の上端の位置を示します。

よって②が①よりも小さければ、要素は表示領域内に入っているということです。

この例では、そのタイミングでアニメーションを再生して、イベントを削除しています。ちなみに例では①から100px引いて動きを確認しやすくしています。

要素が画面に入った瞬間にアニメーションを再生して、画面から離れると逆再生

スクロール量にぴったり合わせたアニメーションだと、スクロールしている間しかアニメーションが実行されません。

一度画面に入ったらアニメーションを再生開始すればスクロールが止まってもアニメーションは続きます。もし画面の外に出ようとしたら再生途中であっても逆再生を開始します。

この方法は非常に強力で、例えば強調したい商品を画面内に入ったらフェードイン、画面外に出ようとするとフェードアウトさせる表現が可能になります。

var anim2 = anime({
    targets: '#sample2',
    translateX: 200,
    easing: 'linear',
    duration: 3000,
    autoplay: false
});
document.addEventListener('scroll',function(){
    var windowHeight = window.innerHeight;
    var targetTop = document.getElementById('sample2').getBoundingClientRect().top;
    var targetBottom = targetTop + document.getElementById('sample2').getBoundingClientRect().height;
    if(200<targetBottom&&targetTop<windowHeight-200){
        if(anim2.progress<100){
            if(anim2.reversed) anim2.reverse();
            anim2.play();
        }
    }else{
        if(0<anim2.progress){
            if(!anim2.reversed) anim2.reverse();
            anim2.play();
        }
    }
});

解説

この例ではanime.jsのプロパティを活用します。

anim.progressプロパティはアニメーションが逆再生しているかどうかを返します。要素が画面内にあるときは通常再生したいので、anim.progressプロパティはアニメーションが逆再生しているかどうかを返します。要素が画面内にあるときは通常再生したいので、anim.reverse()メソッドで再生方向を変えています。anim.reverse()メソッドは現在の再生方向を反対にするのです。要素が画面外にあるときは逆再生していなければ再生方向を変更します。

anim.progressプロパティはアニメーションの現在の進行度を0~100の間で返します。要素が画面内にあるときにすでにアニメーションが100%実行されていれば、改めて再生する必要はありません。逆に画面外にあるときに0%であれば逆再生する必要もありません。

ここでは新たにelement.getBoundingClientRect().heightを使っています。これは要素の高さを取得します。要素の上端の位置と要素の高さを足すことで、要素の下端の位置を取得できます。

スクロール量に合わせてアニメーション

この例はこのページに入った瞬間から始まっていました。画面の右下でぐるぐると回転している棒がそれです。

var anim3 = anime({
    targets: '#sample3',
    rotate: '-1turn',
    easing: 'linear',
    duration: 1000,
    autoplay: false
});
document.addEventListener('scroll',function(){
    var windowHeight = window.innerHeight;
    var pageHeight = document.body.clientHeight;
    var scrollTop = (window.pageYOffset !== undefined) ? window.pageYOffset : document.documentElement.scrollTop || document.body.scrollTop;
    if(0<pageHeight-windowHeight)
        anim3.seek(anim3.duration*scrollTop/(pageHeight-windowHeight));
});

解説

何かの値に合わせてアニメーションする方法はとても簡単です。anim.seek(anim.duration*割合)を実行します。

(window.pageYOffset !== undefined) ? window.pageYOffset : document.documentElement.scrollTop || document.body.scrollTopで現在スクロール量を取得します。ブラウザによって取得方法が異なりますので。このような長い記述となります。スクロールの最大値はページの高さdocument.body.clientHeightから表示領域の高さを引けば求めることができます。

割合がマイナスやInfinityにならないように分母が正の数のときのみ実行していますが、ほとんどの場合このif文は必要ありません。

anime.jsでパララックス

ここまでの内容を応用すれば、簡単にanime.jsでパララックスを実現できます。

#sample4{
    width: 100%;
    height: 40vw;
    background: url("sample4.jpg") no-repeat;
    background-size: 100% auto;
}
var anim4 = anime({
    targets: '#sample4',
    backgroundPositionY: ['100%','0%'],
    easing: 'easeInOutSine',
    duration: 1000,
    autoplay: false
});
document.addEventListener('scroll',function(){
    var windowHeight = window.innerHeight;
    var targetTop = document.getElementById('sample4').getBoundingClientRect().top;
    var targetHeight = document.getElementById('sample4').getBoundingClientRect().height;
    var targetBottom = targetTop + targetHeight;
    if(0<targetBottom&&targetTop<windowHeight){
        if(windowHeight+targetHeight)
            anim4.seek(anim4.duration*targetBottom/(windowHeight+targetHeight));
    }
});

<

section class="explanation">

解説

この例のパララックスは以下の条件で動いています。

  • 要素が表示領域の中央に来た時に画像の中央が表示される
  • 要素が表示領域に入った時に画像の上端が、表示領域から出る時に下端が表示される。

画像を要素の背景に指定し、background-positionプロパティを変化させています。

seekする割合の分子は要素の下端としています。要素が表示領域に入った時に要素の下端は、表示領域の高さ+要素の高さの位置にあります。これが要素の下端の最大値になりますので、分母とします。

アニメーションの動きを変えたいときは、backgroundPositionY: ['100%','0%']easing: 'linear'を変更することで簡単に実現できます。

<

p style="text-align:center">・