本記事では<img>
の最適化について話します
最適するために、以下の観点を考えるべきです
- fetchPriority
- preload
- 画面サイズに応じた画像解像度の重要性
- CLS点を下がるため、
height
とwidth
属性を設定するべき - Base64を避ける
- Lazy Loading
- ツールを紹介
fetchPriority
メリット
ブラウザーが他の画像と比較して、画像の取得をどのように優先させるべきかというヒントを表します。
-
high
他の画像と比較して高い優先度で画像を取得 -
auto
デフォルト値 -
low
他の画像と比較して低い優先度で画像を取得
注意点
何の画像もhighと設定したら優先画像がありません。その為、必要な画像のみを設定するべきです。例えば、ファーストビュー背景画像
深い分析
以下の模擬コードを用意します。同じ画像を9枚表示します。 一枚目に優先高いで取得
<h1>test fetchpriority</h1>
<img src="/test0.JPG" height="200" width="100" fetchpriority="high" />
<img src="/test1.JPG" height="200" width="100" fetchpriority="low" />
<img src="/test2.JPG" height="200" width="100" fetchpriority="low" />
<img src="/test3.JPG" height="200" width="100" fetchpriority="low" />
<img src="/test4.JPG" height="200" width="100" fetchpriority="low" />
<img src="/test5.JPG" height="200" width="100" fetchpriority="low" />
<img src="/test6.JPG" height="200" width="100" fetchpriority="low" />
<img src="/test7.JPG" height="200" width="100" fetchpriority="low" />
<img src="/test8.JPG" height="200" width="100" fetchpriority="low" />
devtoolのnetworkタブでチェック: Priority=lowの画像は恐らく一旦ペンディングされて、他の画像が取得した後で、取得されます。一方、Priority=highと設定された画像はいつも最初に取得されます
Preload
定義
プリロード(preload)って事前にユーザーが将来の操作でターゲットリソースを必要とする可能性が高く、したがってブラウザーはリソースを先読みしてキャッシュすることでユーザーの使い勝手を向上させることができる可能性があることをブラウザーに示唆するものです。
模擬コード
<body>
<div id="img"> </div>
<button onclick="addImage()">
add image
</button>
</body>
<script>
const addImage = () => {
const img = new Image(200, 100);
img.src = '/test.jpg';
document.getElementById('img').appendChild(img);
}
</script>
例えば、ボタンを押下すると タグが埋め込まれる仕組みを考えます。これは、ECサイトで商品詳細画像を拡大表示する場面に例えられます。
このとき、画像の事前取得(Preload)を行わない場合、ボタンを押下した瞬間に画像のダウンロードが始まるため、すぐに反映されません
プリロード
<head>
<!-- ページに入る時、一旦画面を取得しておく -->
<link rel="preload" href="/test.jpg" as="image" />
<!-- -->
</head>
<body>
<div id="img"> </div>
<button onclick="addImage()">
add image
</button>
</body>
<script>
const addImage = () => {
const img = new Image(200, 100);
img.src = '/test.jpg';
document.getElementById('img').appendChild(img);
}
</script>
ページロードする時に、自動的に取得してキャッシュされます。そのため、ボタンを押下するとすぐに反映されます。
注意点
- disable cachedにチェックを入れたら、プリフェッチできない
- 多くの画像をプリフェッチしたら、ウェブが重くなってしまう
- それで必要で静的な画像をプリフェッチ
画面サイズに応じた画像解像度の重要性
ウェブサイトやアプリで画像を表示する際、画面サイズに適した解像度の画像を選ぶことはとても重要です。画像の解像度が高ければ高いほど、ファイルサイズも大きくなり、データの送信や表示に時間がかかってしまいます。
例えば、スマートフォンの小さな画面で高解像度の画像を表示しても、ユーザーが低解像度との差を感じることはほとんどありません。しかし、無駄に大きなファイルサイズになってしまい、モバイルネットワーク(4G・5G)では読み込み時間が長くなる可能性があります。
そこで活用したいのが「レスポンシブ画像」です。HTMLの<img srcset>や<picture>
要素を使うことで、ブラウザがデバイスの画面サイズや解像度に応じて最適な画像ファイルを自動で選択できます。srcset
属性で複数の解像度の画像を指定し、sizes
属性で表示サイズをCSSピクセル単位で指定すると良いでしょう。さらに、モバイル向けとデスクトップ向けで画像のトリミングやフォーマットを変えたい場合は、要素とメディアクエリを使うことで柔軟に対応できます。
DPR(Device Pixel Ratio)について
DPRは「デバイスピクセル比」の略で、1CSSピクセルあたりの実際の物理ピクセル数を示します。例えば、DPRが2のスマートフォンでは、1CSSピクセルが2×2の物理ピクセルに相当します。高DPRのデバイスでは、より細かい表示が可能ですが、その分画像の解像度も高く設定する必要があります。srcset属性に「2x」や「3x」の画像を用意することで、DPRの高い端末でも鮮明な画像を表示できます。
画像ピクセル数:低 | 画像ピクセル数:高 | |
---|---|---|
DPR:低 | ・表示は十分きれい ・ファイルサイズ小 ・読み込み速い |
・表示は非常にきれい ・ファイルサイズ大 ・読み込み遅い可能性あり |
DPR:高 | ・表示がぼやける ・ファイルサイズ小 ・高精細端末では画質不足 |
・表示は鮮明できれい ・ファイルサイズ大 ・読み込み遅い可能性あり |
・画像ピクセル数が低い場合、低DPRの画面では問題なく表示できますが、高DPRの端末だとぼやけてしまいます。
・画像ピクセル数が高い場合、どちらのDPRでもきれいに表示されますが、ファイルサイズが大きくなるため、読み込み時間や通信量に注意が必要です。
最適化のためには、画面のDPRに応じて適切な画像解像度を選択することが重要です。srcset
やpicture
を使うことで、このマトリックスに沿って自動的に最適な画像を配信できます。
Dev toolでDPR確認方法
CLS点が上がらないように、なるべき画像の寸法を設定するべきだ
定義
CLSとはCumulative Layout Shiftです。読み込み中でレイアウトがどれだけずれるかを数値化したものです。以下の感じです
CLS点が高いデメリット
- 検索順位に影響: CLSはGoogleのページエクスペリエンス・ランキングファクターに含まれる主要指標の1つです。つまり、CLSが最適でない場合、ウェブページの検索ランキングに影響を与える可能性があります。
- ユーザー体験に影響: 何かを読んだり、何かをクリックしようとしたとき、突然ページが移動して、場所を見失ってしまいます
そのため、Browerに画像はどのぐらい占めるを教えるべきです。
height
とwidth
それとも aspect-ratio
属性を設定す
imgのsrcをBase64として設定するのを避ける
データベースにimgを直接に保存する案件があります。フロントエンドに画像を返す時には、画像をBASE64でエンコードさせて、以下のようにimgのsrcを設定します。
<img alt="" src="data:image/png;base64,iVBORw0KGgoAhEUgAAA ... FTkSuQmCC" />
また
.div{
background-image: url(data:image/png;base64,iVBORw0KGgoAAAA ... uQmCC);
}
デメリット
- ユーザーのブラウザーでデコード処理があるのでCPUが増える
- HTMLそれともCSSファイルサイぞが増えて、全体ページの読み込み時間が増える
- SEOに悪い影響を与える。SEOのcrawler botは物凄くデータを分析されから
- 元画像よりBase64エンコードされた画像はファイル量が高い
解説
Base64の1記号で6ビットという前提です。
元画像は3記号(1記号=8バイト。3*8=24ビット)だとBase64エンコードされた画像サイズは24ビット/6=4記号です。
→元画像3記号をBase64でエンコードしたら4記号かかります。
Base64使用の場合
デメリットだらけですが、どんな場合を使ってもいいのか?
→軽い画像を表示する時使えます
Lazy loading
こちらは延長読み込みです。私はそれについての記事を書きました。詳細をご覧ください。
その他
画像サイズ下げる
- 画像サイズを下げるが、品質が変わらないツール
-
.wepP
に画像の拡張を変更したら、品質が変わらなくてサイズ下げ荒れる
参考
- https://coralogix.com/guides/real-user-monitoring/cumulative-layout-shift-fix/
- https://web.dev/articles/optimize-cls#images-without-dimensions
- https://developer.mozilla.org/en-US/docs/Glossary/Base64
- https://bunny.net/blog/why-optimizing-your-images-with-base64-is-almost-always-a-bad-idea/
- https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/fetchPriority
- https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/srcset
- https://developer.mozilla.org/ja/docs/Web/HTML/Attributes/rel/prefetch
- https://www.sitepoint.com/how-to-build-responsive-images-with-srcset/