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

2019-10-17
Writing by Jyu

近年、スクロール連動型アニメーションを取り入れているサイトはよく見ますよね。要素が画面中央に達したタイミングでフェードイン表示させたりするアニメーションです。
過去に紹介した、「AOS」もスクロール連動型アニメーションを簡単に実装できるプラグインですが、制作を行っていると、プラグインを導入するまでもないと感じる時があります。それは、スクロールに連動させる箇所が少なかったり、アニメーションが1,2パターンの場合などですね。

 

プラグイン内のファイルには、様々なコードが記述してあり、上記のような場合、必要でないコードの方が多くなります。ですので、その際は自作しても良いと思います。不必要なコードはできる限り含めないほうがいいです。

 

そこで今回は、jQueryを使用したスクロール連動型アニメーションの実装方法を紹介します。

TOPICS

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

ここでは、シンプルなスクロール連動型アニメーションを実装していきたいと思います。

 

DEMO1の仕様は以下の通りです。

要素が画面中央に達したタイミングで0.6秒かけて、50%の大きさから、100%(元の大きさ)の大きさに拡大させながらフェードイン表示。

 

初めにデモをご覧ください。

 

HTML

以下が全体のHTMLコードとなります。

 

<section class="single">
  <div class="wrap">
    <h2>DEMO 1</h2>
    <p class="js-trigger fade-type-scale">テキスト。テキスト。テキスト。</p>
    <p class="js-trigger fade-type-scale">テキスト。テキスト。テキスト。</p>
    <p class="js-trigger fade-type-scale">テキスト。テキスト。テキスト。</p>
    <p class="js-trigger fade-type-scale">テキスト。テキスト。テキスト。</p>
  </div>
</section>

 

かなりシンプルですね。
それでは解説していきたいと思います。

 

<p class="js-trigger fade-type-scale">テキスト。テキスト。テキスト。</p>

 

class=”js-trigger”
こちらがトリガーとなります。
要素が画面中央に達したかを判定する際に必要となります。

 

class=”fade-type-scale”
アニメーション時のスタイルや動きを指定するためのクラスとなります。

CSS

以下が全体のCSSコードとなります。

 

.fade-type-scale{
  text-align: center;
  transition: .6s;
  transform: scale(.5);
  opacity: 0;
  margin-bottom: 100px;
}

.fade-type-scale:last-of-type{
  margin-bottom: 0;
}

.fade-scale{
  transform: scale(1);
  opacity: 1;
}

 

それでは解説していきたいと思います。
※スタイル等の解説は、割愛しております。

 

.fade-type-scale{
  text-align: center;
  transition: .6s;
  transform: scale(.5);
  opacity: 0;
  margin-bottom: 100px;
}

 

transition: .6s;
0.6秒かけてアニメーションさせたいので、transition: .6s を指定します。

 

transform: scale(.5);
アニメーション時に50%の大きさから、100%(元の大きさ)の大きさに拡大させながら表示したいので、transform: scale(.5)を指定し、50%の大きさに設定します。

 

opacity: 0;
デフォルトでは、opadity: 0とし、非表示にします。

 

.fade-scale{
  transform: scale(1);
  opacity: 1;
}

 

こちらアニメーション後のスタイルとなります。
トリガーが画面中央に達したタイミングでjQuery側で、こちらのクラスをつけることでアニメーションを再現することが可能となります。

 

transform: scale(1);
transform: scale(1)を指定し、アニメーション時に元の大きさに戻るよう設定します。

 

opacity: 1;
opacity: 1 を指定し、透明度0の状態から0.6秒かけて表示されるようにします。

jQuery

以下が全体のjQueryコードとなります。

 

$(function(){

  $(window).scroll(function (){
    var fadeTrigger = $('.js-trigger');
    $(fadeTrigger).each(function(){
      var scroll = $(window).scrollTop(),
          elemTop = $(this).offset().top,
          windowHeight = $(window).height();

      if (scroll > elemTop - windowHeight / 2){
        $(this).addClass('fade-scale');
      }
    });
  });
  $(window).trigger('scroll');

});

 

それでは解説していきたいと思います。

 

$(window).scroll(function (){

});

 

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

 

var fadeTrigger = $('.js-trigger');

 

変数fadeTriggerにトリガーとなる class=”js-trigger” を格納します。

 

$(fadeTrigger).each(function(){

});

 

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

 

var scroll = $(window).scrollTop(),
   elemTop = $(this).offset().top,
     windowHeight = $(window).height();

 

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

 

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

 

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

 

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

 

// 発火位置を「画面中央」に設定する場合
if (scroll > elemTop - windowHeight / 2){
 $(this).addClass('fade-scale');
}

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

 

ここでは、「トリガーが画面中央に達したかそうでないか」を判定し、達した場合にfade-scaleクラスを指定し、アニメーションを実行しています。
今回のDEMOでは、発火位置を「画面中央」に設定しておりますが、実装しているともう少し下に設定したい場合も出てきます。その際のカスタマイズもかなり簡単ですので、参考にしてみてください。

 

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

 

リロード時などに、fade-scaleクラスが外れてしまうのを防いでいます。
今回の処理では、スクロール時に「処理に必要となる要素の位置情報を常に監視、取得し、その情報に基づいて、画面中央に達したかを判定し、アニメーションを実行している」と説明しました。ですが、仮に要素が画面中央に達していた場合でも、リロードなど、再読み込みをかけてしまうと変数に格納されていた位置情報がリセットされてしまい、指定したはずのクラスが外れてしまうといったことが起こります。1pxでもスクロールし、スクロールイベントを発火させれば、各要素の位置情報が再度、変数に格納され元の状態に戻りますが、これですと見栄えもよくありませんし、想定していた挙動と異なった結果になってしまいます。なので、JavaScriptファイルが読み込まれた際に意図的にスクロールイベントを発生させ、各変数に再度位置情報を格納し、上記の挙動を回避しています。

 

trigger()メソッドは、任意のタイミングで指定したイベントを実行することができるjQueryメソッドで、引数にはイベントを指定します。windowに対して、.trigger(‘scroll’)を指定することで実際にはスクロールを行なっていないにも関わらず、スクロールイベントを発生させることが可能になります。

 

.trigger(‘scroll’)は、スクロール系の処理でよく使用しますので覚えておくといいです!

以上で、DEMO1の実装が完了となります。

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

ここでは、「一斉にフェードインさせる」スクロール連動型アニメーションを実装していきたいと思います。なお、各要素は時間差でフェードインさせたいと思います。

 

DEMO2の仕様は以下の通りです。

トリガーが画面中央に達したタイミングで0.6秒かけて、50px下の位置から、元の位置に戻りながらフェードイン表示。また、各要素は0.1秒起きに実行させる。

 

初めにデモをご覧ください。

 

※DEMO1と異なる箇所のみ解説していきます。

HTML

以下が全体のHTMLコードとなります。

 

<section class="multiple">
  <div class="wrap">
    <h2>DEMO 2</h2>
    <div class="js-trigger">
      <p class="fade-elem">テキスト。テキスト。テキスト。</p>
      <p class="fade-elem">テキスト。テキスト。テキスト。</p>
      <p class="fade-elem">テキスト。テキスト。テキスト。</p>
      <p class="fade-elem">テキスト。テキスト。テキスト。</p>
      <p class="fade-elem">テキスト。テキスト。テキスト。</p>
      <p class="fade-elem">テキスト。テキスト。テキスト。</p>
      <p class="fade-elem">テキスト。テキスト。テキスト。</p>
    </div>
  </div>
</section>

 

それでは解説していきたいと思います。

 

<div class="js-trigger">
  <p class="fade-elem">テキスト。テキスト。テキスト。</p>
  <p class="fade-elem">テキスト。テキスト。テキスト。</p>
  <p class="fade-elem">テキスト。テキスト。テキスト。</p>
  <p class="fade-elem">テキスト。テキスト。テキスト。</p>
  <p class="fade-elem">テキスト。テキスト。テキスト。</p>
  <p class="fade-elem">テキスト。テキスト。テキスト。</p>
  <p class="fade-elem">テキスト。テキスト。テキスト。</p>
</div>

 

DEMO1と異なる箇所はこちらだけですね!

DEMO2では、トリガーが画面中央に達したタイミングでトリガー内の要素を一斉フェードインさせたいので、トリガーとなるdivに対してjs-triggerクラスを、フェードイン要素となるpに対してfade-elemクラスを指定します。

CSS

以下が全体のCSSコードとなります。

 

.fade-elem{
  text-align: center;
  transition: .6s;
  transform: translateY(50px);
  opacity: 0;
  margin-bottom: 10px;
}

.fade-elem:last-of-type{
  margin-bottom: 0;
}

.fade-elem:nth-of-type(2){transition-delay: .1s;}
.fade-elem:nth-of-type(3){transition-delay: .2s;}
.fade-elem:nth-of-type(4){transition-delay: .3s;}
.fade-elem:nth-of-type(5){transition-delay: .4s;}
.fade-elem:nth-of-type(6){transition-delay: .5s;}
.fade-elem:nth-of-type(7){transition-delay: .6s;}

.fade-up{
  transform: translateY(0);
  opacity: 1;
}

 

それでは解説していきたいと思います。
※スタイル等の解説は割愛しております。

 

.fade-elem{
  text-align: center;
  transition: .6s;
  transform: translateY(50px);
  opacity: 0;
  margin-bottom: 10px;
}

 

transform: translateY(50px);
アニメーション時に50px下の位置から、元の位置に戻りながら表示させたいでの、translateY(50px)を指定し、50px下の位置に配置します。

 

.fade-elem:nth-of-type(2){transition-delay: .1s;}
.fade-elem:nth-of-type(3){transition-delay: .2s;}
.fade-elem:nth-of-type(4){transition-delay: .3s;}
.fade-elem:nth-of-type(5){transition-delay: .4s;}
.fade-elem:nth-of-type(6){transition-delay: .5s;}
.fade-elem:nth-of-type(7){transition-delay: .6s;}

 

各フェードイン要素にtransition-delayを指定し、0.1秒おきにアニメーションが実行されるよう設定します。transition-delayには、「トランジションが開始されるまでの時間」を指定することができます。
従って、
1つ目の要素は0秒後(デフォルト)にアニメーション開始
2つ目の要素は0.1秒後にアニメーション開始
3つ目の要素は0.2秒後にアニメーション開始
・・・
とタイムラグをもたせることが可能となります。

 

.fade-up{
  transform: translateY(0);
  opacity: 1;
}

 

こちらアニメーション後のスタイルとなります。
transform: translateY(0);
transform: translateY(0)を指定し、アニメーション時に元の位置に戻るように設定します。

jQuery

以下が全体のjQueryコードとなります。

 

$(function(){

  $(window).scroll(function (){
    var fadeTrigger = $('.js-trigger');
    $(fadeTrigger).each(function(){
      var scroll = $(window).scrollTop(),
          elemTop = $(this).offset().top,
          windowHeight = $(window).height();

      if (scroll > elemTop - windowHeight / 2){
        $(this).find('.fade-elem').addClass('fade-up');
      }
    });
  });
  $(window).trigger('scroll');

});

 

それでは解説していきたいと思います。

 

$(this).find('.fade-elem').addClass('fade-up');

 

DEMO1,2と異なる箇所は、こちらだけですね!
今回、フェードインさせたいのはトリガー内のp要素(fade-elemクラスが指定されている要素)ですので、find()メソッドを使用して、fade-upクラスの指定先をp要素に変更し、完了となります。

DEMO2に関しても、特に難しく感じる箇所はなかったと思います。
タイムラグをもたせ一斉にフェードインさせる処理は、実務でも頻出しますので、ぜひ覚えておいてください!

複数パターンの実装

DEMO1は「fade-scale」、DEMO2は「fade-up」とDEMO1,2ともにアニメーションタイプは一種類だけでしたが、実務を行なっているとfede-upやfade-left, fade-rightなど複数のアニメーションタイプが必要となる場合があります。その際の実装法について解説していきたいと思います。

 

初めにデモをご覧ください。

 

※DEMO1,2と異なる箇所のみ解説していきます。

HTML

以下が全体のHTMLコードとなります。

 

<section class="multiple-type">
  <div class="wrap">
    <h2>DEMO 3</h2>
    <p class="js-trigger fade-type-down">テキスト。テキスト。テキスト。</p>
    <p class="js-trigger fade-type-up">テキスト。テキスト。テキスト。</p>
    <p class="js-trigger fade-type-left">テキスト。テキスト。テキスト。</p>
    <p class="js-trigger fade-type-right">テキスト。テキスト。テキスト。</p>
    <div class="js-trigger multi-trigger">
      <p class="fade-elem">テキスト。テキスト。テキスト。</p>
      <p class="fade-elem">テキスト。テキスト。テキスト。</p>
      <p class="fade-elem">テキスト。テキスト。テキスト。</p>
      <p class="fade-elem">テキスト。テキスト。テキスト。</p>
      <p class="fade-elem">テキスト。テキスト。テキスト。</p>
      <p class="fade-elem">テキスト。テキスト。テキスト。</p>
    </div>
  </div>
</section>

 

それでは解説していきたいと思います。

 

<p class="js-trigger fade-type-down">テキスト。テキスト。テキスト。</p>
<p class="js-trigger fade-type-up">テキスト。テキスト。テキスト。</p>
<p class="js-trigger fade-type-left">テキスト。テキスト。テキスト。</p>
<p class="js-trigger fade-type-right">テキスト。テキスト。テキスト。</p>

 

各アニメーションのスタイルや動きを指定するための「fade-type-***」クラスを指定します。

クラス名 アニメーション内容
fade-type-up 50px下の位置から0pxの位置に戻るようアニメーション
fade-type-down 50px上の位置から0pxの位置に戻るようアニメーション
fade-type-left 50px右の位置から0pxの位置に戻るようアニメーション
fade-type-right 50px左の位置から0pxの位置に戻るようアニメーション

 

<div class="js-trigger multi-trigger">
  <p class="fade-elem">テキスト。テキスト。テキスト。</p>
  <p class="fade-elem">テキスト。テキスト。テキスト。</p>
  <p class="fade-elem">テキスト。テキスト。テキスト。</p>
  <p class="fade-elem">テキスト。テキスト。テキスト。</p>
  <p class="fade-elem">テキスト。テキスト。テキスト。</p>
  <p class="fade-elem">テキスト。テキスト。テキスト。</p>
</div>

 

class=”multi-trigger”
jQuery側で、「単体フェードイン、一斉フェードイン」を判定するためのクラスとなります。

  • multi-triggerクラスあり、一斉フェードイン
  • multi-triggerクラスなし、単体フェードイン

CSS

以下が全体のCSSコードとなります。

 

.fade-type-up,
.fade-type-down,
.fade-type-left,
.fade-type-right,
.fade-elem{
  text-align: center;
  transition: .6s;
  opacity: 0;
  margin-bottom: 100px;
}

.fade-elem{
  margin-bottom: 10px;
}

.fade-elem:last-of-type{
  margin-bottom: 10px;
}

.fade-type-up,
.fade-elem{
  transform: translateY(50px);
}

.fade-type-down{
  transform: translateY(-50px);
}

.fade-type-left{
  transform: translateX(50px);
}

.fade-type-right{
  transform: translateX(-50px);
}

.fade-elem:nth-of-type(2){transition-delay: .1s;}
.fade-elem:nth-of-type(3){transition-delay: .2s;}
.fade-elem:nth-of-type(4){transition-delay: .3s;}
.fade-elem:nth-of-type(5){transition-delay: .4s;}
.fade-elem:nth-of-type(6){transition-delay: .5s;}
.fade-elem:nth-of-type(7){transition-delay: .6s;}

.fade-up-down{
  transform: translateY(0);
  opacity: 1;
}

.fade-left-right{
  transform: translateX(0);
  opacity: 1;
}

 

それでは解説していきたいと思います。
※スタイル等の解説は割愛しております。

 

.fade-type-up,
.fade-elem{
  transform: translateY(50px);
}

.fade-type-down{
  transform: translateY(-50px);
}

.fade-type-left{
  transform: translateX(50px);
}

.fade-type-right{
  transform: translateX(-50px);
}

 

アニメーション前の位置を指定しています。

 

.fade-up-down{
  transform: translateY(0);
  opacity: 1;
}

.fade-left-right{
  transform: translateX(0);
  opacity: 1;
}

 

こちらアニメーション後のスタイルと位置になります。
fade-type-upとfade-type-down、fade-type-leftとfade-type-rightは、アニメーション後のスタイルが同じになりますので、共通化しています。

jQuery

以下が全体のjQueryコードとなります。

 

$(function(){

  $(window).scroll(function (){
    var fadeTrigger = $('.js-trigger');
    $(fadeTrigger).each(function(){
      var scroll = $(window).scrollTop(),
          elemTop = $(this).offset().top,
          windowHeight = $(window).height();

      if (scroll > elemTop - windowHeight / 2){
        if ($(this).hasClass('multi-trigger')) {
          $(this).find('.fade-elem').addClass('fade-up-down');
        } else if ($(this).hasClass('fade-type-up') || $(this).hasClass('fade-type-down')) {
          $(this).addClass('fade-up-down');
        } else if ($(this).hasClass('fade-type-left') || $(this).hasClass('fade-type-right')) {
          $(this).addClass('fade-left-right');
        }
      }
    });
  });
  $(window).trigger('scroll');

});

 

それでは解説していきたいと思います。

 

if ($(this).hasClass('multi-trigger')) {
  $(this).find('.fade-elem').addClass('fade-up-down');
} else if ($(this).hasClass('fade-type-up') || $(this).hasClass('fade-type-down')) {
  $(this).addClass('fade-up-down');
} else if ($(this).hasClass('fade-type-left') || $(this).hasClass('fade-type-right')) {
  $(this).addClass('fade-left-right');
}

 

DEMO1,2と異なる箇所は、こちらだけですね!
hasClass()メソッドを使用して、multi-triggerクラスの有無とアニメーションタイプを確認し、判定しています。

 

if文の条件を見てみましょう。
$(this).hasClass(‘multi-trigger’)
class=”multi-trigger”が指定されていた場合、一斉フェードインとなるため、トリガー内のp要素に対して、fade-up-downクラスを指定します。

 

$(this).hasClass(‘fade-type-up’) || $(this).hasClass(‘fade-type-down’)
clacc=”fade-type-up”またはclacc=”fade-type-down”が指定されていた場合、fade-up-downクラスを指定します。

 

$(this).hasClass(‘fade-type-left’) || $(this).hasClass(‘fade-type-right’)
clacc=”fade-type-left”またはclacc=”fade-type-right”が指定されていた場合、fade-left-rightクラスを指定します。

 

以上で、複数のアニメーションタイプが存在する際の実装が完了となります。
とても簡単でしたよね。もちろんコピペOKですので、みなさん是非試してみてください!

まとめ

今回は、jQueryを使用したスクロール連動型アニメーションの実装法を紹介しました。

 

導入箇所やアニメーションパターン、個別設定の有無など条件によってはプラグインを使用した方が効率が良かったりもするので、ご自身でどちらを取り入れるか検討してみて下さい!

 

また、スクロール連動型アニメーションを簡単に実装できるプラグイン「AOS」は、以下の記事で紹介しています。アニメーションパターンや詳細設定なども豊富なプラグインですので、ご興味のある方は、ぜひ!!