フェードしながら画像を遅延読み込みする機能を実装する方法
Webサイトの表示速度を早める方法としてよく用いる画像の遅延読み込み。スクロールしたときにそのまま画像が表示されるだけでも十分ですが、ちょっとしたインタラクションを追加して、より良いユーザ体験を提供したいです。そこで今回は、遅延読み込みした画像をフェードしながら表示するアイデアを紹介します。
目次
設計
Mediumのインタラクションを参考に、次のように設計します。
- ページがロードされた状態では読み込する前の画像(以降、プレースホルダー画像と呼ぶ)を表示し、CSSでぼかしエフェクトを加える。
- 画像がビューポートに入るタイミングで読み込み後の画像(以降、オリジナル画像と呼ぶ)を読み込む。
- 読み込みが完了したタイミングでプレースホルダー画像をフェードアウトさせる。
- スクリプトが実行されない場合は、オリジナル画像を表示する。
前回の記事に引き続き、画像の遅延読み込みにはyall.jsを用います。yall.jsの使い方については前回の記事で触れていますので、確認してみてください。なお、遅延読み込み画像のロード完了イベントが画像ごとに発火するJavaScriptプラグインであれば、ほかのプラグインでも実装できます。
実装サンプル
See the Pen Lazy loading image to fade in by lyzon-sasaki (@lyzon-sasaki) on CodePen.
実装サンプルではyall.jsをインラインで記述しています。また、画像はダミー画像サービスを利用しています。
実装
画像の用意
画像の遅延読み込みには、オリジナル画像とプレースホルダー画像の2つを用意します。プレースホルダー画像は、オリジナル画像より縮小し、圧縮率を高めた荒い画像にします。パフォーマンスをさらに向上させるためには、オリジナル画像も表示されるコンテンツ幅に合わせたサイズとするべきでしょう。
今回はテスト用の画像として、Photoshopでオリジナル画像とプレースホルダー画像を作成しました。
種別 | サイズ | 保存時の画質 |
---|---|---|
オリジナル画像 | 600x400 | 12 |
プレースホルダー画像 | 60x40 | 0 |
CMSなどで画像が管理されているWebサイトであれば、クエリパラメーターなどを用いて画像を縮小・圧縮すれば、画像を複数作成する手間が省けるでしょう。
HTML
JavaScriptが無効だった場合のトリガーとなるクラスをhtml
要素に付与します。JavaScriptが有効だった場合は、JavaScriptでこのクラスを削除します。
<html class="no-js">...</html>
次に、スクリプトを読み込みます。かならずpolyfillを先読みしてください。
<!-- IntersectionObserverが使用できないブラウザのためのpolyfillを読み込み -->
<script src="https://polyfill.io/v3/polyfill.min.js?features=IntersectionObserver"></script>
<!-- yall.js本体を読み込み -->
<script src="yall.min.js"></script>
続いて、遅延読み込みをする画像のマークアップをします。
<!-- 遅延読み込みをする画像の単位 -->
<div class="lazyLoadImage">
<!-- プレースホルダー画像 小さい画像を引き伸ばして使用するため、height/width属性にはオリジナル画像の画像サイズを入力 alt属性は利用しない -->
<img class="lazyLoadImage__placeholder" src="photo-placeholder.jpg" alt="" height="400" width="600">
<!-- 遅延読み込みされるオリジナル画像 yall.jsのトリガーとなる`lazy`クラスを付与 alt属性を記入 -->
<img class="lazyLoadImage__original lazy" data-src="photo.jpg" alt="awesome photo" height="400" width="600">
<!-- JavaScriptが無効だった場合にオリジナル画像が表示されるようにフォールバック -->
<noscript>
<img src="photo.jpg" alt="awesome photo" height="400" width="600">
</noscript>
</div>
CSS
スタイルは次のような設計とします。
- プレースホルダー画像はCSS Filter
filter: blur()
でボケさせ、自然なボケになるようtransform: scale()
で少しはみ出させる。 - オリジナル画像はプレースホルダー画像の上に被せるように
position: absolute
絶対座標とする。 - オリジナル画像は読み込み前を
opacity: 0
として、遅延読み込みが完了したタイミングでopacity: 1
にアニメーションさせる。
これをもとにスタイルを書きます。
.lazyloadimage {
background-color: #f1f2f3;
display: inline-block; /* img要素と同じふるまいになるようにする */
overflow: hidden; /* プレースホルダー画像のはみだしを隠す */
position: relative; /* オリジナル画像を絶対座標にする */
}
.lazyloadimage img {
vertical-align: middle; /* 画像の下にできる余白を消す */
}
.lazyloadimage__placeholder {
filter: blur(20px); /* ぼかし(IE11は非対応) */
transform: scale(1.1); /* ぼかしを自然にする */
}
.lazyloadimage__original {
height: 100%; /*position/top/left/width/heightでプレースホルダー画像と同じ大きさにする */
left: 0;
opacity: 0; /* 初期状態で不透明度を0にする */
position: absolute;
top: 0;
transition: opacity .5s .5s; /* 遅延読み込み後、opactyを0.5秒さらに遅延させ0.5秒かけてアニメーションさせる */
width: 100%;
}
.lazyloadimage__original.yall-loaded {
opacity: 1; /* 遅延読み込み完了時付与された.yall-loadedをトリガーにして不透明度を1にする */
}
.no-js .lazyloadimage__placeholder,
.no-js .lazyloadimage__original {
display: none; /* JavaScriptが無効のときに、プレースホルダー画像とオリジナル画像を非表示にする */
}
JavaScript
JavaScriptは至って簡単で、プラグインのREADMEに記載されているコードをそのまま流用します。
// JavaScriptが有効の場合はno-jsクラスを外す
document.documentElement.classList.remove("no-js");
document.addEventListener("DOMContentLoaded", function () {
// yall.jsの実行
yall({
events: {
load: function () {
if (!event.target.classList.contains("lazy") && event.target.nodeName == "IMG") {
// 読み込み完了後にyall-loadedクラスを付与
event.target.classList.add("yall-loaded");
}
}
}
});
});
まとめ
以上、遅延読み込みした画像をフェードしながら表示するアイデアの紹介でした。単に遅延読み込みするだけでも十分パフォーマンスは向上しLighthouse等のスコアも挙げられますが、さらにインタラクションを加えてよりダイナミックな表現をすることで、ユーザー体験が向上されるのではないでしょうか。
ほかにも色々なインタラクションを調査研究し、紹介できればと思います。

2014年入社。安定感や清潔感のあるデザインが得意。CMSに導⼊しやすい効率的かつ保守性の⾼いマークアップができ、デザイナーながらフロントエンドの技術も有する。
旅と写真が好きだが、地図を眺めていて1日が終わることがよくある。