模写修行メディア

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

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

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

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

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

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

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

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

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

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

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

👇 メンターやってます 👇

模写修行やこのメディアを作ったエンジニア中心に、メンタリングサービスHello Mentorを運営しています。

0からweb制作やプログラミングの勉強を始める方はもちろん、12ヶ月以上独学している方や既にお仕事をしている方にもご利用いただいています!

模写武者くんのアイコン
  • 独学に限界を感じている...
  • 何をどこまで勉強すれば良いかわからない...
  • 自分の書き方が正しいかわからない...
  • 検索しても解決しない問題が多い...
  • 転職や副業のアドバイスが欲しい...

このような方は、ぜひ下記のリンクからサービス詳細をご覧ください。無料相談もお気軽にお申し込みください。

※ 少人数運営のため人数制限あり ※

詳しいサービス内容を見る

入会金/解約料/契約期間の縛りなし

👆 メンターやってます 👆

この記事の目次

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

要素が画面下部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')を指定することで実際にはスクロールを行なっていなくても、スクロールイベントを発生させることが可能になります。

【初学者・中級者の方】独学に限界を感じてませんか?

プログラミングやデザインは独学可能ですが、ほとんんどの方が苦戦します。

↓このように感じていませんか?

  • 何をどこまで勉強すれば良いかわからない...
  • 自分の書き方が正しいかわからない...
  • 検索しても解決しない問題が多い...
  • 転職や副業するまでの道が見えない...

そんな問題を解決するために、模写修行やこのメディアを作ったエンジニア/デザイナー中心に、メンタリングサービスHello Mentorを始めました。

初級者から中級者まで対応できる、数少ないサービスです。

スクールのような大金は必要ありません。高額な費用は払いたくないけど、プロのサポートが欲しい方は、ぜひ下記のリンクからサービス詳細をご覧ください。

※ 少人数運営のため人数制限あり ※

詳しいサービス内容を見る

入会金/解約料/契約期間の縛りなし

👆 メンターは全員現役エンジニア 👆

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

要素が画面下部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をいじるだけで、カスタマイズも出来ます。

独学に限界を感じていませんか?

現役エンジニアによるメンタリングサービス作りました!

模写修行やこのメディアを作ったエンジニア中心に、メンタリングサービスHello Mentorを運営しています。

👇 こんな方のためのサービスです。

  • 独学に限界を感じている...
  • 何をどこまで勉強すれば良いかわからない...
  • 自分の書き方が正しいかわからない...
  • 検索しても解決しない問題が多い...
  • 転職や副業のアドバイスが欲しい...

メンターを務めるのは、今も現役でコードを書いているエンジニアのみです。駆け出しの方やメンターだけをやっている方はいません。

高額な料金はかかりません。サブスク / 契約期間の縛りなし / 入会金・解約料なしなので、リスクなく始められます。

少しでも興味がある方は、ぜひ下記のリンクからサービスサイトをご覧ください。無料相談もお気軽にお越しください。(無理な営業等一切ございません!)

※ 少人数運営のため人数制限あり ※

詳しいサービス内容を見る

入会金/解約料/契約期間の縛りなし

この記事を書いた人

Tatsukiのアイコン

Tatsuki

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

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

詳しく見る

\Share/

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

実務レベルを体験するためのコーディング練習教材