模写修行メディア

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

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

簡単に実装できるライブラリは多くありますが、以下のような点で導入しづらいケースもあります。

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

自作すると自由度が高く、上のようなデメリットを回避できます。今回は、JavaScript(jQuery)を使用したスクロールアニメーションの実装方法を紹介します。

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

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

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

【超簡単】JavaScriptライブラリaos.jsの使い方を解説!

JavaScriptの基礎学習がまだの方は、下記の記事も参考にしてみてください。

JavaScriptの勉強ができるおすすめの本やサイト紹介!

👇 メンターやってます 👇

模写修行やこのメディアを作ったメンバー中心に、Web制作業界を目指す方のための学習支援サービス 『Hello Mentor』 を運営しています。

基礎学習後に迷子になっていませんか?脱初心者したいなら、私たちにお任せください!

模写武者くんのアイコン
  • 基礎学習後にやるべきことがわからない...
  • スクール卒だけど実力不足だと感じている...
  • 自分のコードが正しい書き方かわからない...
  • 未経験から1人で転職できる気がしない...
  • 独立するためのノウハウがない...

特に上記のような方は、ぜひ下記のリンクからサービス詳細をご覧ください。

受け入れ人数制限あり

詳しく見る

サブスクで入会金・解約金・最低契約期間もなし

Hello MentorのLINEを登録すると、過去ウェビナーの一部をプレゼントしています。また、今後開催するウェビナーや講義にも無料で参加できるチャンスがあります。

👆 無料でプレゼント 👆

この記事の目次

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

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

シンプルなスクロールアニメーションを実装します。要素が画面下部200pxに達したタイミングで0.6秒かけて、50px下の位置から、フェードアップさせます。

  1. HTMLを記述する
  2. CSSを記述する
  3. JavaScript(jQuery)を記述する

この流れで紹介します。

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>
</section>
Point
役割ごとにクラスを分けることで、管理しやすいコードになります。

💡 class=”single-item"

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

💡 class=”u-fade-type-up"

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

💡 class=”js-scroll-trigger"

トリガー用のクラスです。JavaScript側で要素が画面下部200pxに達したかを判定する際に必要となります。「js-」がついているクラスは、JavaScriptから操作するクラスなので、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)を記述する

$(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関数を実行します。

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

💡 関数呼び出

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

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

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

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

💡 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');

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

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

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

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

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

.each()は、指定した要素や配列、オブジェクトなどに対し、ループ処理を行うメソッドです。

$(".js-scroll-trigger")に対して指定することで、サイト内の全トリガー要素に対して、以下の処理を適応させていることになります。

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

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

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

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

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

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

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

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

今回のDEMOでは、発火位置を「画面下部 200px」に設定してますが、実装していると「画面中央」に設定したい場合も出てきます。

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

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

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

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

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

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

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

基礎学習後...迷子になっていませんか?

Web制作業界を目指す方の多くが、基礎学習後にやるべきことがわからず、迷子状態になっています。あなたも下記のように感じていませんか?

  • 基礎学習後にやるべきことがわからない...
  • スクール卒だけど実力不足だと感じている...
  • 自分のコードが正しい書き方かわからない...
  • 未経験から1人で転職できる気がしない...
  • 独立するためのノウハウがない...

そんな悩みを解決するために、模写修行やこのメディアを作ったエンジニア・デザイナー中心に、学習支援サービス 『Hello Mentor』 を運営しています。

転職成功者や副業・フリーランスデビューした方も出ています。

受け入れ人数制限あり

詳しく見る

サブスクで入会金・解約金・最低契約期間もなし

Hello MentorのLINEを登録すると、過去ウェビナーの一部をプレゼントしています。また、今後開催するウェビナーや講義にも無料で参加できるチャンスがあります。

👆 無料でプレゼント 👆

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

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

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

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

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

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>
</section>

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

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のみで実装する

// トリガー取得
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をいじるだけで、カスタマイズも出来ます。

基礎学習後...迷子になっていませんか?

模写修行やこのメディアを作ったメンバー中心に、Web制作業界を目指す方のための学習支援サービス 『Hello Mentor』 を運営しています。

下記のような、基礎学習後にやるべきことがわからず、迷子状態になっている方に特におすすめです

  • 基礎学習後にやるべきことがわからない...
  • スクール卒だけど実力不足だと感じている...
  • 自分のコードが正しい書き方かわからない...
  • 未経験から1人で転職できる気がしない...
  • 独立するためのノウハウがない...

メンターは、全員が現役のプロです。駆け出しの方やメンターだけをやっている方はいません。

少数精鋭で運営しているため、受け入れ人数に限りがあります。本気でWeb制作業界を目指している方は、ぜひご検討ください。

受け入れ人数制限あり

詳しく見る

サブスクで入会金・解約金・最低契約期間もなし

Hello MentorのLINEを登録すると、過去ウェビナーの一部をプレゼントしています。また、今後開催するウェビナーや講義にも無料で参加できるチャンスがあります。

この記事を書いた人

Tatsukiのアイコン

Tatsuki

空間コーディネーターから独学でプログラミングを学びwebの世界へ。コーディングが好き。普段はHTML・CSS / JavaScript / Reactを主に書いています。

当メディア運営メンバーでメンターやってます!👉

詳しく見る

\Share/

模写修行のトップページのスクリーンショット
模写修行

駆け出しコーダー向けコーディング練習教材