🎉 お知らせ:サイト名が『webkore』から『模写修行 media』に変更になりました。6月以降にドメインも『moshashugyo.com/media/』へ変更する予定です。

JavaScript

JavaScript(jQuery)でスクロール連動型アニメーションを自作する方法を解説!

Author:Jyu

この記事の目次

スクロール連動型アニメーションを取り入れているサイト誰でも一度はみたことがあるのではないでしょうか?

スクロール連動型アニメーションを簡単に実装できるプラグインは多くありますが、以下のような点で導入しづらいケースもあります。

  • アニメーションタイプが限定されている
  • カスタマイズが難しい
  • 不要なコードが含まれている
  • 複数のプラグインを使用する場合、プラグイン同士が干渉して、正常に動作しないことがある

このようなデメリットを回避するには、自作する必要があります。そこで今回は、JavaScript(jQuery)を使用したスクロール連動型アニメーションの実装方法を紹介します。

HTML・CSSを追加するだけアニメーションタイプを増やせたり、なるべく汎用性があるようにしました。

基本的にjQueryを使って解説しますが、使わない場合も同じ考え方です。最後にはJavaScriptのみで行うコードも記載したので、参考にしてみてください。

まずはプラグインを使って簡単に実装してみたい方は、下記の記事も参考にしてみてください!

単体でフェードインさせる

要素が画面下部200pxに達したタイミングで0.6秒かけて、50px下の位置から、フェードアップさせる図

まずはシンプルなスクロール連動型アニメーションを実装します。

仕様

要素が画面下部200pxに達したタイミングで0.6秒かけて、50px下の位置から、フェードアップさせます。

デモもご覧ください。

HTMLを記述する

html
<section class="single">
    <h2>DEMO1</h2>

      <div class="single-item u-fade-type-up js-scroll-trigger">
          <img src="img/sample.jpg" alt="">
      </div>

      <div class="single-item u-fade-type-up js-scroll-trigger">
          <img src="img/sample.jpg" alt="">
      </div>

      <div class="single-item u-fade-type-up js-scroll-trigger">
          <img src="img/sample.jpg" alt="">
      </div>

      <div class="single-item u-fade-type-up js-scroll-trigger">
          <img src="img/sample.jpg" alt="">
      </div>

      <div class="single-item u-fade-type-up js-scroll-trigger">
          <img src="img/sample.jpg" alt="">
      </div>
</section>
Point

役割ごとにクラスを分けています。そうすることで、管理しやすいコードになります。

class=”single-item"

レイアウトや見た目のスタイルを指定するためのクラスです。こちらのクラスには、アニメーション関連のCSSは指定しません。

class=”u-fade-type-up"

アニメーション時のスタイルや動きを指定するためのクラスです。アニメーション関連のスタイルは全てこちらのクラスに指定します。「u-」は、「utility」の「u」です。

class=”js-scroll-trigger"

トリガー用のクラスです。JavaScript側で要素が画面下部200pxに達したかを判定する際に必要となります。「js-」がついているクラスは、JavaScriptから操作するクラスなので、CSSの指定はしません。

CSSを記述する

css
/* レイアウトや見た目のスタイル */
/* ---------------------------- */

.single-item + .single-item{
    margin-top: 80px;
}

/* アニメーションスタイル */
/* ---------------------------- */

/* アニメーション前 */
.u-fade-type-up{
    transform: translateY(50px);
    opacity: 0;
}

/* トリガー発火でis-activeを付与 */
.u-fade-type-up.is-active{
    transition: .6s;
    transform: translateY(0);
    opacity: 1;
}

アニメーション前

transform: translateY(50px);で要素を50px下の位置に配置して、かつopacity: 0;で透明にして、見えなくしています。

トリガー発火

要素が画面下部200pxに達したタイミングで、JavaScriptでis-activeクラスを付与します。0.6秒かけて、透明度と位置を元に戻します。

JavaScript(jQuery)を記述する

javascript
$(function () {

    // aimation呼び出し
    if ($('.js-scroll-trigger').length) {
        scrollAnimation();
    }

    // aimation関数
    function scrollAnimation() {
        $(window).scroll(function () {
            $(".js-scroll-trigger").each(function () {
                let position = $(this).offset().top,
                    scroll = $(window).scrollTop(),
                    windowHeight = $(window).height();

                if (scroll > position - windowHeight + 200) {
                    $(this).addClass('is-active');
                }
            });
        });
    }
    $(window).trigger('scroll');

});

処理は関数化しています。 ページ内にjs-scroll-triggerクラスが存在した場合、スクロール連動型アニメーションの処理であるscrollAnimation関数を実行します。

少し長いので、分割して解説します。


関数呼び出

javascript
// aimation呼び出し
if ($('.js-scroll-trigger').length) {
    scrollAnimation();
}

scrollAnimation関数の呼び出しを行っています。

if文の条件$('.js-scroll-trigger').lengthは、ページ内にjs-scroll-triggerクラスが存在した場合「true」となり、関数呼び出しが行われます。反対にページ内にjs-scroll-triggerクラスが存在しなかった場合は、呼び出しは行われません。

scrollAnimation関数は、常に実行していても問題ないのですが、js-scroll-triggerクラスの有無を確認した上で、関数を実行するか否かを判断している理由は、scrollAnimation関数内にscrollイベントが含まれており、このscrollイベントは比較的負荷の高い処理になります。従って、ページ内にスクロール連動アニメーションが存在した場合にのみ、処理を実行しています。


scrollAnimation関数

javascript
// aimation関数
function scrollAnimation() {
    $(window).scroll(function () {
        $(".js-scroll-trigger").each(function () {
            let position = $(this).offset().top,
                scroll = $(window).scrollTop(),
                windowHeight = $(window).height();

            if (scroll > position - windowHeight + 200) {
                $(this).addClass('is-active');
            }
        });
    });
}
$(window).trigger('scroll');

1番重要な箇所で、長くなるので、この中のコードをさらに分割して解説します。

javascript
$(window).scroll(function (){});

スクロールに連動させるためには、常に処理に必要となる要素の位置を監視、取得しなければなりません。従って、scrollイベントを使用し、スクロール時に処理が行われるようにします。

javascript
$(".js-scroll-trigger").each(function(){});

eachメソッドを使用し、全トリガー要素(class=”js-scroll-trigger”が指定されている要素)に対して処理を適応させます。

.each()は、指定した要素や配列、オブジェクトなどに対し、ループ処理を行うメソッドとなります。従って、$(".js-scroll-trigger")に対して指定することで、サイト内の全トリガー要素に対して、以下の処理を適応することが可能となります。

javascript
let position = $(this).offset().top,
    scroll = $(window).scrollTop(),
    windowHeight = $(window).height();

ここでは、「トリガーが画面下部200pxに達したか」を判定するために必要な情報を変数に格納しています。

.offset().topは、ドキュメント最上部を基準に指定要素の位置のY座標を戻り値として返します。従って、変数positionには各トリガーの垂直方向の位置が格納されます。

scrollTop()メソッドは、垂直方向のスクロール位置を戻り値として返します。従って、$(window)に対して、.scrollTop()を指定することで、ブラウザのスクロール位置を取得することが可能となります。

$(window).height()ではウィンドウの高さを取得し、格納しています。

javascript
// 発火位置を「画面下部から200pxの位置」に設定する場合
if (scroll > position - windowHeight + 200){
    $(this).addClass('is-active');
}

// 発火位置を「画面中央」に設定する場合はこちら
if (scroll > position - windowHeight / 2){
    $(this).addClass('is-active');
}

「トリガーが画面下部200pxに達した」と判定した場合、is-activeクラスを付与しています。

今回のDEMOでは、発火位置を「画面下部200px」に設定してますが、実装していると「画面中央」に設定したい場合も出てきます。その際の調整も簡単なので、参考にしてみてください。

javascript
$(window).trigger('scroll');

リロード時などに、is-activeクラスが外れてしまうのを防いでいます。

今回は「処理に必要となる要素の位置情報を常に監視、取得し、その情報に基づいて、画面下部200pxに達したかを判定し、アニメーションを実行」しています。

しかし、仮に要素が画面下部200pxに達していた場合でも、リロードなど、再読み込みをかけてしまうと変数に格納されていた位置情報がリセットされてしまい、指定したはずのクラスが外れてしまいます。

従って、JavaScriptファイルが読み込まれた際に意図的にスクロールイベントを発生させ、各変数に再度位置情報を格納しています。

trigger()メソッドは、任意のタイミングで指定したイベントを実行することができるjQueryメソッドで、引数にはイベントを指定します。

windowに対して、.trigger('scroll')を指定することで実際にはスクロールを行なっていなくても、スクロールイベントを発生させることが可能になります。

一斉にフェードインさせる

要素が画面下部200pxに達したタイミングで複数の要素を0.4秒おき0.6秒かけて、50px下の位置から、フェードアップさせる図

今まで解説した内容は、要素単体でのフェードアップでしたが、ここでは、あるトリガーに達したら、「一斉にフェードインさせる」スクロール連動型アニメーションを実装します。

仕様

要素が画面下部200pxに達したタイミングで複数の要素を0.4秒おきに一斉にフェードアップさせます。また、フェードアップの挙動に関しては、DEMO1同様0.6秒かけて、50px下の位置から実行します。

JavaScriptはDEMO1と全く同じです。HTML・CSSを少し変更するだけで簡単に実装できます。※DEMO1と異なる箇所のみ解説していきます。

デモもご覧ください。

HTMLを記述する

html
<section class="multiple">
    <h2>DEMO2</h2>

    <div class="multiple-list js-scroll-trigger">
        <div class="multiple-item u-fade-type-up">
            <img src="img/sample.jpg" alt="">
        </div>

        <div class="multiple-item u-fade-type-up">
            <img src="img/sample.jpg" alt="">
        </div>

        <div class="multiple-item u-fade-type-up">
            <img src="img/sample.jpg" alt="">
        </div>

        <div class="multiple-item u-fade-type-up">
            <img src="img/sample.jpg" alt="">
        </div>

        <div class="multiple-item u-fade-type-up">
            <img src="img/sample.jpg" alt="">
        </div>

        <div class="multiple-item u-fade-type-up">
            <img src="img/sample.jpg" alt="">
        </div>
    </div>
</section>

トリガーが画面下部200pxに達したタイミングでトリガー内の要素を一斉フェードインさせたいので、トリガーとなるdivに対してjs-scroll-triggerクラスを、フェードイン要素となるdivに対してu-fade-type-upクラスを指定します。

CSSを記述する

css
/* レイアウトや見た目のスタイル */
/* ---------------------------- */

.multiple-list{
    display: flex;
    justify-content: space-between;
    flex-wrap: wrap;
}

.multiple-item{
    width: 49%;
    margin-top: 20px;
}

.multiple-item:nth-child(-n+2){
    margin-top: 0;
}

/* アニメーションスタイル */
/* ---------------------------- */

/* アニメーション前 */
.u-fade-type-up{
    transform: translateY(50px);
    opacity: 0;
}

/* トリガー発火でis-activeを付与 */
.is-active .u-fade-type-up{
    transition: .6s;
    transform: translateY(0);
    opacity: 1;
}

.is-active .u-fade-type-up:nth-child(2){transition-delay: .4s;}
.is-active .u-fade-type-up:nth-child(3){transition-delay: .8s;}
.is-active .u-fade-type-up:nth-child(4){transition-delay: 1.2s;}
.is-active .u-fade-type-up:nth-child(5){transition-delay: 1.6s;}
.is-active .u-fade-type-up:nth-child(6){transition-delay: 2s;}

@media screen and (min-width: 768px) {
    .multiple-item{
        width: 32%;
    }

    .multiple-item:nth-child(-n+3){
        margin-top: 0;
    }
}

アニメーションスタイル

DEMO1の単体フェードインは、フェードイン要素にis-activeがつきましたが、一斉フェードインでは、フェードイン要素ではなく、親要素のトリガーにis-activeがつきます。アニメーション後のスタイル指定は.is-active .u-fade-type-upのようになります。

各要素を0.4秒おきにフェードアップしたいので、transition-delayを利用し、遅延実行しています。1つ目の要素は、トリガーにis-activeがついたと同時に実行され、2つ目の要素は0.4秒後、3つ目の要素は0.8秒後...に実行されます。

delayは、jQuery側で指定することも可能ですが、今回はCSS側で指定しています。基本的にスクロール連動は、限られた箇所でしか利用しないので、CSS側で指定した方が良いかなと思います。

jQueryを使わずにJavaScriptのみで実装する

javascript
// トリガー取得
const scrollTrigger = document.querySelectorAll('.js-scroll-trigger');

// aimation呼び出し
if (scrollTrigger.length) {
    scrollAnimation(scrollTrigger);
}

// aimation関数
function scrollAnimation(trigger) {
    window.addEventListener('scroll', function () {
        for (var i = 0; i < trigger.length; i++) {
            let position = trigger[i].getBoundingClientRect().top,
                scroll = window.pageYOffset || document.documentElement.scrollTop,
                offset = position + scroll,
                windowHeight = window.innerHeight;

            if (scroll > offset - windowHeight + 200) {
                trigger[i].classList.add('is-active');
            }
        }
    });
}

jQueryを利用せず、ネイティブのJavaScriptで実装する際は、上記のコードに変更してください。やっていることは、jQuery版と同じです。

コードに関して気になる方は、ご自身で調べてみてください。

応用例のサンプル

応用例としてサンプルをいくつか作成しました。

サンプルデモのアニメーションはJavaScriptは今まで解説したコードで、HTML・CSSのみ追加したものになります。このようにHTML・CSSをいじるだけで、カスタマイズも出来ます。

駆け出しエンジニアのためのコーディング練習教材

Coming Soon
© 2021 模写修行 media.