JavaScriptとCSSを使ったスライドショーで画像を遅延ロードする方法
すまない、”また”スライドショーの話なんだ。
最初に投稿した「JavaScriptでスライドショーみたいな画像切替え(jQueryなし)」ではJavaScriptのsetTimeout関数、およびCSSのdisplayプロパティのnone/blockを切り替えることで画像のスライドショーを実現しました。
そして、2回目の「JavaScriptとCSSで画像をふわっと切り替えるスライドショーを作る」ではsetTimeoutは変わらないものの、transitionプロパティを使うことで、画像をふわりと切り替えるサンプルを作りました。あとついでにスライドショーの速度もリアルタイムで切り替えられるように。
そこで今回はまだ表示していない画像はロードせず、表示される番になってはじめてロードするという、いわゆる遅延ロードを組み込みたいと思います。
なぜ遅延ロードが必要なのか
スライドショーを何枚表示するかにもよりますが、仮に100枚くらい表示するとしたら、ページの初回表示の時点で残りの99枚もの画像をロードしておく、なんていうのは時間的にも通信量的にも無駄です。
例えば1ページあたり平均1~2分くらいしか滞在しないサイトの場合、5秒に1枚写真をスライドさせるとして、1分間で12枚ですから、平均して24枚切り替わるかどうか。
前述のように100枚くらいスライドがあったとしたら、残り76枚分の画像のロード処理は無駄でしかありませんよね。もちろんもっと早く別ページへ移動する人も多くいるはずなのであくまで平均の話。
それに最近の検索エンジンはページの初回表示の速度も評価対象に入っており、SEO対策としても大事なようです。そのためか、画像の遅延ロードをするためのJavaScriptライブラリもよく見かけるようになりましたよね。
じゃあそれ使えば良いじゃんって話ですが、いやいやいや、(ぼくの場合は)せっかく趣味としてプログラミングしているのだからそこは自分で実装してみたいな、と考えました。………それに、スライドショーに限って言うなら、既存コードに3行追加するくらいで出来そうだったのでw
実行例
今回に限って言えば先に実行例見せたところで見た目には変わらないのですが…、でもChromeやEdge Chromiumを使っている方なら、[開発ツール](Ctrl+Shift+I)からネットワークタブを見るとわかりやすいかも知れません。このページを表示した後、5秒に1回新しい画像が読み込まれるのが視覚的に確認できるハズです。
速度:
HTML部分の解説
<div class="slide">
<img data-src="[画像01]" />
<img data-src="[画像02]" />
<img data-src="[画像03]" />
<img data-src="[画像04]" />
<img data-src="[画像05]" />
<img data-src="[画像06]" />
<img data-src="[画像07]" />
<img data-src="[画像08]" />
</div>
<p>速度:<input type="range" id="slide_speed" value="5000" min="0" max="10000"></p>
HTML部分については前回の「JavaScriptとCSSで画像をふわっと切り替えるスライドショーを作る」から何も変わっていない…………と言いたいところですが、とても重要なところが変わっています。
そう、imgタグのsrcを指定していません。変わりにdata-src属性を指定しています。これはHTML5で追加されたカスタムデータ属性というもので、「data-ほにゃらら」という形で、自分の好きな属性を追加できる仕組み。CSSで利用することもできますが、今回はJavaScriptでこのdata-srcを読み取ります。
要するに、このHTMLの時点ではimgタグのsrcに何も指定されていないため、ブラウザは画像の読み込み処理を一切しないわけですね。
CSS部分の解説
<style>
.slide img {
display:none;
animation:anime 1s;
}
@keyframes anime {
from { opacity:0; }
to { opacity:1; }
}
</style>
ここも前回からあまり変わっていない…………と言いたいところでしたが、前回はtransitionを使うために相対座標指定して画像を重ね合わせる小細工をしたため、ちょっとCSSが長すぎたかなーと思いまして。今回はtransitionではなく、keyframesを使うことでもっとシンプルにしました。
ほら、画像の重ね合わせだとdivタグの高さを指定したりobject-fitで画像のリサイズさせたり、ちょっぴり複雑になっちゃうじゃないですか。なので、displayプロパティのnone/blockを切り替えただけでアニメーションされるよう、transitionを廃止し、keyframesを導入した感じです。
この書き方ならJavaScript側でdisplayプロパティを変更した際に、ちゃんと毎回アニメーションしてくれるのですよ。
JavaScript部分の解説
<script>
window.addEventListener('load', function () {
viewSlide('.slide img');
});
function viewSlide(className, slideNo = -1)
{
let imgArray = document.querySelectorAll(className);
if (slideNo >= 0) { //初回以外は現在のスライドを消す
imgArray[slideNo].style.display = 'none';
}
slideNo++;
if (slideNo >= imgArray.length) {
slideNo = 0; //次のスライドがなければ最初のスライドへ戻る
}
if (imgArray[slideNo].src == '') { //未ロード画像はロードする
imgArray[slideNo].src = imgArray[slideNo].dataset.src;
}
imgArray[slideNo].style.display = 'block';
let msec = document.getElementById('slide_speed').max - document.getElementById('slide_speed').value;
setTimeout(function(){viewSlide(className, slideNo);}, msec);
}
</script>
さて、ここが遅延ロードのキモとなる部分ですが、ぶっちゃけ3行しか変わっていません。
if (imgArray[slideNo].src == '') { //未ロード画像はロードする
imgArray[slideNo].src = imgArray[slideNo].dataset.src;
}
…………これだけ。
imgタグのsrc属性が指定されていない場合、datasetのsrc、つまり先述のHTMLで data-src="[画像]" と記述した部分、このファイル名をセットしているだけです。
img.srcにimg.data-srcをセットする。ただそれだけでブラウザ側は画像をロードして表示してくれるというわけですね。
まとめ
いやほんとドヤ顔で解説するような内容の記事じゃないんですけど、”遅延ロード”なんて仰々しい名前が付いているとプログラミング初心者の方は難しく考えてしまうのではないかなぁー、なんて思いまして。
実際は
- HTMLのカスタムデータ属性に画像ファイルの場所(URL)を書いておく
- ロードしたいタイミングでimgタグのsrcにカスタムデータ属性(data-src)のURLをセットする
という、ただそれだけの動作なんだよー、というお話でした。
これだけだと、あまりにアレなので、オマケとしてCSSのtransitionを使わず、keyframesアニメーションでふわっと画像を表示する例も追加してみた感じです。
では、そんな感じで、この記事がどこかの誰かのお役に立てば幸いでございます。