JavaScript以外で画像をキャッシュさせないほうが良い

Webサイトで画像を先読みしてキャッシュ

:hoverやDOMでモーダルなどを表示させる際に画像が遅れて表示されるWebサイトをよく見かける。

画像が遅れて表示されるのはユーザー側のアクションによってまだ読み込まれていない画像の読み込みが開始されるのが原因だ。

これを防ぐためには画像を事前に読み込む必要があるのだが、そのための主な方法は以下の4つが存在する。

  1. CSSスプライト画像による先読み
  2. CSS backgroundの複数指定による先読み
  3. link rel="preload"による先読み
  4. JavaScriptによる先読み

しかし、1.から3.は現在ではデメリットが大きいのであまりオススメしない。

1. CSSスプライト画像による先読み

CSSスプライト画像による先読みとは画像内に複数の画像を入れて最初は一部分だけ見せる手法。

例えば以下のように画像を2つ入れて最初は左部分を表示してhover時に右部分を表示させるようにする。

こうすればカエル部分は最初からブラウザで読み込まれているのでhover時に読み込まれることはない。

CSSスプライト画像

マウスオーバーで画像切替

.img-sprite {
  width: 200px;
  height: 200px;
  background: url(https://iwb.jp/s/img/img_sprite.png) no-repeat;
  background-size: 400px auto;
  cursor: pointer;
}

.img-sprite:hover {
  background-position: top right;
}

しかし、現在は画像ファイルはGitHubで管理されることが多く、CSSスプライト用の画像を別途生成して管理しなければならないというデメリットがあるので現在では使用されていることは少ない。

2. CSS backgroundの複数指定による先読み

CSSのbackgroundは複数の背景画像を指定できるので以下のようにhover時に見せる画像を最初に見せる画像の下に配置すれば画像の先読みが可能となる。

.sample {
  width: 200px;
  height: 200px;
  background: url(https://iwb.jp/s/img/img.png) no-repeat,
              url(https://iwb.jp/s/img/img_hover.png) no-repeat;
  background-size: 200px auto;
  cursor: pointer;
}

.sample:hover {
  background-image: url(https://iwb.jp/s/img/img_hover.png);
}

この方法はhover時の画像を下に配置しているので、上の画像が透過だと使えない。

あと該当箇所のCSSの要素の部分に記述しなければならないので一括で管理しづらい。

3. link rel="preload"による先読み

HTMLコード内にlinkタグにrel="preload"で画像のパスを記述することで画像の先読みが可能になる。

<link rel="preload" href="https://iwb.jp/s/img/img_hover.png" as="image">

しかし、この手法は先読みさせる画像の数だけlinkタグが必要になってしまってHTMLコードの可読性が低下するので、あまり使用されていない。

4. JavaScriptによる先読み

JavaScriptによる先読みは以下のコードの用に先読みする画像のURLを配列で指定してforEachで読み込む。

間違えて他の画像より先に読み込まないようwindow.onload内で実行する。

window.onload = () => {
  const images = [
    'https://iwb.jp/s/img/img_hover.png',
  ]
  images.forEach(v => new Image().src = v)
}

JavaScriptファイル内での記述であればHTMLやCSSに記述するよりも管理しやすいし、読み込み順なども制御できる。

以上の理由により画像を先読みする際は1.から3.のやり方ではなく4.のJavaScriptを使用した方法を使用したほうが良いだろう。

JavaScriptによる画像先読みサンプル