スクロールしたら要素をフェードインしたり動かしたりする方法【JavaScript】

JavaScript

企業サイトやゲーム公式サイトなどでよくみかけるWebページのギミックですね。ブラウザをスクロールしていたら画面内に入ってきた要素が横から現れたり、ふわっとフェードインしたりする視覚効果を実装する方法のご紹介です。出来るだけ初心者の方にも分かるようにしましたのでご参考にしてみてください。

ふわっとフェードインするサンプルと解説

まず、基本となる考え方を以下のようなフローで想定することが出来ます。仕組みを理解すればいかようにも応用出来るのでまずはこのサンプルのロジックを押さえておきましょう。

  1. HTMLで出現させたい要素を書いておく(class名を付与しておく)
    idだと1ページに1ヶ所しか置けないルール(W3C)なのでclassにすること。
  2. CSSで1を非表示にしておく
    ※非表示の方法はいろいろありますがとりあえずdisplay: none;にしておきましょう。
  3. JavaScriptでブラウザ(画面)の一番上から要素までの距離(高さ・px数)を取得して計算
    ※ウィンドウの上端とエレメントの上端の距離です。
  4. スクロールイベントを利用して、ウィンドウの高さより3の高さが小さくなる瞬間に新しいクラス(display: block;にするクラス)を付けるJavaScriptを書く。
    ※実際にはif (elementTop - windowHeight <= 0)のような形で条件分岐を付けます。
  5. 4で付けたクラスによってアニメーションするCSSを作成&調整していく。
    ※1で付けたクラスとスクロール時に4で付けるクラスは別物なので注意してください。

では最も簡単なサンプルを示します。

<!-- アニメーションさせたいコンテンツをここに配置 -->
<div class="animateElement">  
</div>
<!-- // ここまでアニメーションさせたいコンテンツ -->
.animateElement {
  width: 100%; /* これはテスト用のサイズ指定なのでなくていいです */
  height: 5em; /* これはテスト用のサイズ指定なのでなくていいです */
  background: #000; /* これはテスト用のサイズ指定なのでなくていいです */
  -webkit-transform: translateZ(0); /* 動きを滑らかにするおまじないです。使いすぎ注意。 */
 display: none;
  opacity: 0:
}

.animated {
  /* アニメーションのプロパティを指定 */
  animation-name: example;
  animation-duration: 1s;
  display: block;
  opacity: 1;

}

@keyframes example {
  from {opacity: 0;}
  to {opacity: 1;}
}
window.addEventListener("scroll", function () {
  // アニメーションを実行したいエレメントを取得
  const element = document.getElementsByClassName("animateElement");

  // ウィンドウの上端とエレメントの上端の距離を取得
  const elementTop = element[0].getBoundingClientRect().top;
  const windowHeight = window.innerHeight;

  // アニメーションの条件をチェック
  if (elementTop - windowHeight <= 0) {
    // アニメーションを実行するためのコードをここに記述
    element.classList.add("animated");
  }
});

ふわっと出ます

ただこのサンプルには欠点があり、animateElementクラスが複数あっても最初の一つしか動作しません。<div class="animateElement"></div>で囲ったエリアをすべて同じようにふわっと表示させたい場合には下記のようにJavaScriptのループ処理を行う必要があります。

window.addEventListener("scroll", function () {
  // アニメーションを実行したいエレメントを取得
  const elements = document.getElementsByClassName("animateElement");

  // 複数のエレメントに対して、アニメーションを実行する
  Array.prototype.forEach.call(elements, function (element) {
    // ウィンドウの上端とエレメントの上端の距離を取得
    const elementTop = element.getBoundingClientRect().top;
    const windowHeight = window.innerHeight;

    // アニメーションの条件をチェック
    if (elementTop - windowHeight <= 0) {
      // アニメーションを実行するためのコードをここに記述
      element.classList.add("animated");
    }
  });
});

ふわっと出ます

prototypecallを使っているので少々面喰いますが、このコードをコピペすれば動くのでもし理解出来なくてもそのまま流用してしまってください。
prototypeについては『プロトタイプ(prototype)の基礎、メリットやサンプルコードによる実装方法を出来るだけ分かりやすく解説【JavaScript】』、forEach()については『JavaScriptにおけるforEach()とは?基本的なループの使い方と注意点』にまとめてあるので興味あるかたはご覧ください)

ふわっと出ます

説明すると、まずgetElementsByClassNameメソッドを使って、クラス名がanimateElementであるすべてのエレメントを取得しています。で、Array.prototype.forEach.callメソッドを使用して、取得したエレメントのリストに対して、それぞれアニメーションを実行するようにしています。

左から出現させたい場合

これから先のサンプルはすべてCSSを書き換えるだけで実現できます。画面内に入ったら付与されるanimated2クラスに対してアニメーションをかけます。先ほどのJavaScript内に書いた付与クラスはanimated2にしてありますので必要に応じてJavaScriptも書き換えてください。

左から出ます

.animated2 {
  /* アニメーションのプロパティを指定 */
  -webkit-transform: translateZ(0);
  animation-name: example2;
  animation-duration: 0.5s;
  animation-timing-function: ease-in;
  position: relative;
  display: block;
  opacity: 1;
}

@keyframes example2 {
  from {
    opacity: 0;
    left: -100px;
  }
  to {
    opacity: 1;
    left: 0;
  }
}

右から出したい場合

右から出ます

.animated3 {
  /* アニメーションのプロパティを指定 */
  -webkit-transform: translateZ(0);
  animation-name: example3;
  animation-duration: 0.2s;
  position: relative;
  display: block;
  opacity: 1;
}

@keyframes example3 {
  from {
    opacity: 0;
    left: 100px;
  }
  to {
    opacity: 1;
    left: 0;
  }
}

下から出したい場合

下から出ます

まとめ

スクロールで要素が出現するギミックは、JavaScriptではあくまでエレメントにクラスを付与するだけにとどめておくのがコツです。

付与したクラスに対してCSSのanimation@keyframesを使うとどんな感じにでも動かすことが出来ます。プログラムの工数も一番少なくて済みますし、JavaScriptが分からない同僚でも修正や調整が可能です。

上記のようにスクロール時に付与されるCSSを触ってみて好みの動きを実現してみてください。

タイトルとURLをコピーしました