はじめてのページローディング実装

初心者を検索から引っ張ろうとしたタイトルではありません。
私が初めてローディング画面の実装をできた記念の記事です。

要するにどういうことか

リッチなMVやスライドやエフェクトやら使ったサイトは、どうしても読み込みが遅くなります。
訪問者にただ数秒待たせるのが申し訳ないというより、読み込みが完了して表示が整ってからWEBサイトを見てほしいという、製作側の我が儘です。

モーダルウィンドウを設置したことある人はパッと分かると思いますが、要するに本来のWEBページの上にposition: fixed;を使ってブラウザ枠いっぱいの要素を被せるということです。
中のテキストやアニメーションは、gifアニメーションを使うなり、CSSのkeyframesで動かすなりどうにでもなります。

実装!

今回はCSSによるアニメーションの動きを記述する方法でデモを作成します。

<body>
  <!-- ローディング画面 -->
  <div id="loading-wrapper">
    <div class="loader"></div>
    <p>Loading...</p>
  </div>
  <!-- コンテンツ部分 -->
  <div id="page">
    (本来のWEBページのコンテンツ部分)
  </div>
</body>

pタグのテキストはあってもなくてもいいです。

ローディング画面の側

#loading-wrapper { 
  position: fixed;
  top: 0; 
  left: 0; 
  width: 100%; 
  height: 100%; 
  background: #CCC5C1; 
  display: flex; 
  flex-direction: column; 
  justify-content: center; 
  align-items: center; 
  transition: all 0.3s; 
  z-index: 9999;
} 

position: fixed;height: 100%;でブラウザ枠いっぱいのサイズにします。
background: #CCC5C1;ここの背景色は好きな色にして、
display: flex;align-items: center;で、中の要素が中央配置されるようにします。
transition: all 0.3s;これは消えるときのスピードなので適時調整してもらって、
z-index: 9999;で一番上に配置されるように大きな数値を設定します。

ローディングアニメーションの部分

.loader {
  width: 1em;
  height: 1em;
  border-radius: 50%;
  position: relative;
  text-indent: -9999em;
  -webkit-animation: load5 1.1s infinite ease;
  animation: load5 1.1s infinite ease;
  -webkit-transform: translateZ(0);
  -ms-transform: translateZ(0);
  transform: translateZ(0);
}
@-webkit-keyframes load5 {
  0%,
  100% {
    box-shadow: 0em -2.6em 0em 0em #ffffff, 1.8em -1.8em 0 0em rgba(255, 255, 255, 0.2), 2.5em 0em 0 0em rgba(255, 255, 255, 0.2), 1.75em 1.75em 0 0em rgba(255, 255, 255, 0.2), 0em 2.5em 0 0em rgba(255, 255, 255, 0.2), -1.8em 1.8em 0 0em rgba(255, 255, 255, 0.2), -2.6em 0em 0 0em rgba(255, 255, 255, 0.5), -1.8em -1.8em 0 0em rgba(255, 255, 255, 0.7);
  }
  12.5% {
    box-shadow: 0em -2.6em 0em 0em rgba(255, 255, 255, 0.7), 1.8em -1.8em 0 0em #ffffff, 2.5em 0em 0 0em rgba(255, 255, 255, 0.2), 1.75em 1.75em 0 0em rgba(255, 255, 255, 0.2), 0em 2.5em 0 0em rgba(255, 255, 255, 0.2), -1.8em 1.8em 0 0em rgba(255, 255, 255, 0.2), -2.6em 0em 0 0em rgba(255, 255, 255, 0.2), -1.8em -1.8em 0 0em rgba(255, 255, 255, 0.5);
  }
  25% {
    box-shadow: 0em -2.6em 0em 0em rgba(255, 255, 255, 0.5), 1.8em -1.8em 0 0em rgba(255, 255, 255, 0.7), 2.5em 0em 0 0em #ffffff, 1.75em 1.75em 0 0em rgba(255, 255, 255, 0.2), 0em 2.5em 0 0em rgba(255, 255, 255, 0.2), -1.8em 1.8em 0 0em rgba(255, 255, 255, 0.2), -2.6em 0em 0 0em rgba(255, 255, 255, 0.2), -1.8em -1.8em 0 0em rgba(255, 255, 255, 0.2);
  }
  37.5% {
    box-shadow: 0em -2.6em 0em 0em rgba(255, 255, 255, 0.2), 1.8em -1.8em 0 0em rgba(255, 255, 255, 0.5), 2.5em 0em 0 0em rgba(255, 255, 255, 0.7), 1.75em 1.75em 0 0em #ffffff, 0em 2.5em 0 0em rgba(255, 255, 255, 0.2), -1.8em 1.8em 0 0em rgba(255, 255, 255, 0.2), -2.6em 0em 0 0em rgba(255, 255, 255, 0.2), -1.8em -1.8em 0 0em rgba(255, 255, 255, 0.2);
  }
  50% {
    box-shadow: 0em -2.6em 0em 0em rgba(255, 255, 255, 0.2), 1.8em -1.8em 0 0em rgba(255, 255, 255, 0.2), 2.5em 0em 0 0em rgba(255, 255, 255, 0.5), 1.75em 1.75em 0 0em rgba(255, 255, 255, 0.7), 0em 2.5em 0 0em #ffffff, -1.8em 1.8em 0 0em rgba(255, 255, 255, 0.2), -2.6em 0em 0 0em rgba(255, 255, 255, 0.2), -1.8em -1.8em 0 0em rgba(255, 255, 255, 0.2);
  }
  62.5% {
    box-shadow: 0em -2.6em 0em 0em rgba(255, 255, 255, 0.2), 1.8em -1.8em 0 0em rgba(255, 255, 255, 0.2), 2.5em 0em 0 0em rgba(255, 255, 255, 0.2), 1.75em 1.75em 0 0em rgba(255, 255, 255, 0.5), 0em 2.5em 0 0em rgba(255, 255, 255, 0.7), -1.8em 1.8em 0 0em #ffffff, -2.6em 0em 0 0em rgba(255, 255, 255, 0.2), -1.8em -1.8em 0 0em rgba(255, 255, 255, 0.2);
  }
  75% {
    box-shadow: 0em -2.6em 0em 0em rgba(255, 255, 255, 0.2), 1.8em -1.8em 0 0em rgba(255, 255, 255, 0.2), 2.5em 0em 0 0em rgba(255, 255, 255, 0.2), 1.75em 1.75em 0 0em rgba(255, 255, 255, 0.2), 0em 2.5em 0 0em rgba(255, 255, 255, 0.5), -1.8em 1.8em 0 0em rgba(255, 255, 255, 0.7), -2.6em 0em 0 0em #ffffff, -1.8em -1.8em 0 0em rgba(255, 255, 255, 0.2);
  }
  87.5% {
    box-shadow: 0em -2.6em 0em 0em rgba(255, 255, 255, 0.2), 1.8em -1.8em 0 0em rgba(255, 255, 255, 0.2), 2.5em 0em 0 0em rgba(255, 255, 255, 0.2), 1.75em 1.75em 0 0em rgba(255, 255, 255, 0.2), 0em 2.5em 0 0em rgba(255, 255, 255, 0.2), -1.8em 1.8em 0 0em rgba(255, 255, 255, 0.5), -2.6em 0em 0 0em rgba(255, 255, 255, 0.7), -1.8em -1.8em 0 0em #ffffff;
  }
}
@keyframes load5 {
  0%,
  100% {
    box-shadow: 0em -2.6em 0em 0em #ffffff, 1.8em -1.8em 0 0em rgba(255, 255, 255, 0.2), 2.5em 0em 0 0em rgba(255, 255, 255, 0.2), 1.75em 1.75em 0 0em rgba(255, 255, 255, 0.2), 0em 2.5em 0 0em rgba(255, 255, 255, 0.2), -1.8em 1.8em 0 0em rgba(255, 255, 255, 0.2), -2.6em 0em 0 0em rgba(255, 255, 255, 0.5), -1.8em -1.8em 0 0em rgba(255, 255, 255, 0.7);
  }
  12.5% {
    box-shadow: 0em -2.6em 0em 0em rgba(255, 255, 255, 0.7), 1.8em -1.8em 0 0em #ffffff, 2.5em 0em 0 0em rgba(255, 255, 255, 0.2), 1.75em 1.75em 0 0em rgba(255, 255, 255, 0.2), 0em 2.5em 0 0em rgba(255, 255, 255, 0.2), -1.8em 1.8em 0 0em rgba(255, 255, 255, 0.2), -2.6em 0em 0 0em rgba(255, 255, 255, 0.2), -1.8em -1.8em 0 0em rgba(255, 255, 255, 0.5);
  }
  25% {
    box-shadow: 0em -2.6em 0em 0em rgba(255, 255, 255, 0.5), 1.8em -1.8em 0 0em rgba(255, 255, 255, 0.7), 2.5em 0em 0 0em #ffffff, 1.75em 1.75em 0 0em rgba(255, 255, 255, 0.2), 0em 2.5em 0 0em rgba(255, 255, 255, 0.2), -1.8em 1.8em 0 0em rgba(255, 255, 255, 0.2), -2.6em 0em 0 0em rgba(255, 255, 255, 0.2), -1.8em -1.8em 0 0em rgba(255, 255, 255, 0.2);
  }
  37.5% {
    box-shadow: 0em -2.6em 0em 0em rgba(255, 255, 255, 0.2), 1.8em -1.8em 0 0em rgba(255, 255, 255, 0.5), 2.5em 0em 0 0em rgba(255, 255, 255, 0.7), 1.75em 1.75em 0 0em #ffffff, 0em 2.5em 0 0em rgba(255, 255, 255, 0.2), -1.8em 1.8em 0 0em rgba(255, 255, 255, 0.2), -2.6em 0em 0 0em rgba(255, 255, 255, 0.2), -1.8em -1.8em 0 0em rgba(255, 255, 255, 0.2);
  }
  50% {
    box-shadow: 0em -2.6em 0em 0em rgba(255, 255, 255, 0.2), 1.8em -1.8em 0 0em rgba(255, 255, 255, 0.2), 2.5em 0em 0 0em rgba(255, 255, 255, 0.5), 1.75em 1.75em 0 0em rgba(255, 255, 255, 0.7), 0em 2.5em 0 0em #ffffff, -1.8em 1.8em 0 0em rgba(255, 255, 255, 0.2), -2.6em 0em 0 0em rgba(255, 255, 255, 0.2), -1.8em -1.8em 0 0em rgba(255, 255, 255, 0.2);
  }
  62.5% {
    box-shadow: 0em -2.6em 0em 0em rgba(255, 255, 255, 0.2), 1.8em -1.8em 0 0em rgba(255, 255, 255, 0.2), 2.5em 0em 0 0em rgba(255, 255, 255, 0.2), 1.75em 1.75em 0 0em rgba(255, 255, 255, 0.5), 0em 2.5em 0 0em rgba(255, 255, 255, 0.7), -1.8em 1.8em 0 0em #ffffff, -2.6em 0em 0 0em rgba(255, 255, 255, 0.2), -1.8em -1.8em 0 0em rgba(255, 255, 255, 0.2);
  }
  75% {
    box-shadow: 0em -2.6em 0em 0em rgba(255, 255, 255, 0.2), 1.8em -1.8em 0 0em rgba(255, 255, 255, 0.2), 2.5em 0em 0 0em rgba(255, 255, 255, 0.2), 1.75em 1.75em 0 0em rgba(255, 255, 255, 0.2), 0em 2.5em 0 0em rgba(255, 255, 255, 0.5), -1.8em 1.8em 0 0em rgba(255, 255, 255, 0.7), -2.6em 0em 0 0em #ffffff, -1.8em -1.8em 0 0em rgba(255, 255, 255, 0.2);
  }
  87.5% {
    box-shadow: 0em -2.6em 0em 0em rgba(255, 255, 255, 0.2), 1.8em -1.8em 0 0em rgba(255, 255, 255, 0.2), 2.5em 0em 0 0em rgba(255, 255, 255, 0.2), 1.75em 1.75em 0 0em rgba(255, 255, 255, 0.2), 0em 2.5em 0 0em rgba(255, 255, 255, 0.2), -1.8em 1.8em 0 0em rgba(255, 255, 255, 0.5), -2.6em 0em 0 0em rgba(255, 255, 255, 0.7), -1.8em -1.8em 0 0em #ffffff;
  }
}

長いっすね! でも、下記サイトからコピペで持ってきたものです。安心してください。

ローディングアニメーションの部分は色々なサイトで様々な動きが提案されているので、お好みのものを探してみてください。

ここまでのデモページです。ページローディングのぐるぐるしてる状態です。
(テキストがローディングアニメーションに被ったので、margin調整しています)

ページローディングだけのデモ

ページ読み込みが終わったらローディング画面を非表示にする

ここまでで作ったローディング画面を、ページ読み込みが終わったら消す処理を設定します。
やり方は色々あるのですが、複雑なJSは怖いので簡単な方法を試してみます。

画像や関連ファイルを含めたページ読み込みが完了したらJavaScript#loading-wrapper.completedとclassを付加します。

window.onload = function() {
  const loader = document.getElementById('loading-wrapper');
  loader.classList.add('completed');
}

window.onloadイベントハンドラは、ページ読み込みが完了したらイベント発生するぜっていう命令です。詳しくは下記ページを参照してください。

この.completedにCSSで非表示の設定を記述します。

.completed {
  opacity: 0;
  visibility: hidden;
}

デモページ

デモページも作成しましたが、ページ読み込みを遅くするために1.6MBの画像を使用しています。制限ある方は気を付けてください。

ページローディングのデモ

jQueryを使用している場合

前述の例と同じ命令になりますが、もうちょい簡単に記述できます。
こちらもページ読み込みが完了したら#loading-wrapper.completedを付加するイベントが発生します。

$(window).on('load',function(){
  $("#loading-wrapper").addClass("completed")
});
jQuery版ページローディングのデモ

メモ: 時間指定でローディングをフェードアウト

重い動画を埋め込んでいたり、大きいスライドを複数使っていたり、いつまで経ってもページローディングが終わらないこともあります。
その場合は、時間を設定してそれ以上経ったらそっとローディング画面をフェードアウトさせて、(完全に読み込みが終わってないとはいえ)コンテンツ部分を訪問者にお見せする手もあります。
あまりに長いローディング画面は離脱率上昇の要因にもなりますからね。

以下、jQueryの記述です。

setTimeout(function() {
  $('#loading-wrapper').fadeOut(600);
}, 5000); // 5秒後にfadeOut処理

こちらは後述する応用のデモページで実装しています。

応用その1

ローディング画面というとグルグルしていたりするイメージがありますが、別にグルグルにこだわらなくてもいいんですよね。

デモページのキャプチャ

背景→メイン画像→周囲のあしらい画像2つの順に、keyframesで時間差を付けてふわっと表示させます。
5秒経ったらjQueryでローディングをフェードアウトする処理をします。

ページローディングの応用のデモ

応用その2: Lottieアニメーションを配置

デモページのキャプチャ

Lottieアニメーションの設置の仕方については別記事にまとめる予定ですが、ローディングにLottieアニメーションを配置しても表現が広がりますね。(IE非対応です)
こちらも5秒経ったらjQueryでフェードアウトする処理をしています。

Lottieアニメーションでページローディングのデモ

まとめ

ローディングアニメーションが難しそうで、ページローディングの実装はここまで見ないふりしてました。

ローディングアニメーション無しでテキストのみでもいいし、CSSでアニメーションの記述が難しかったらGifアニメーションを配置してもいいし、ブラウザ枠いっぱいに要素を広げる→ページ読み込みでclassを付加→付加されたclassには非表示設定、と分けて考えるとそこまで難易度高くもないんですね。

「全部一塊のすごいJSに違いない!」と変に難しく考え過ぎていました。反省。