レスポンシブサイトでブラウザ環境に応じて画像を切り替えるには、サイトによって様々な方法で対処されていました。
これまでの方法が抱えていたデメリットと現在(これから)の標準となる実装方法、レガシーなブラウザへの対応方法など、レスポンシブな画像切り替えに必要な知識をまとめました。
目次
これまでのレスポンシブイメージの問題点
レスポンシブサイトの画像切り替えは、CSSで表示・非表示を切り替えたり、JavaScriptでブラウザ環境を判別して画像を出し分けると言った手法が一般的でした。
たしかに、これらの方法でも意図したように画像を表示することはできるのですが、理想的な解決策ではありません。
具体的には次のような問題がありました。
- 内容の重複するHTMLを記述しなければならない
- 表示しない画像も全てリクエストして読み込まなければいけない
- スクリプト処理が増えるためレンダリングが遅くなる
総じて、画像を切り替えるために「サイトが重たくなる」という犠牲を前提としていました。
スマートフォンで画像がぼやける問題
現在のレスポンシブサイトは、スマホで閲覧した時に画像が粗くぼやけて見える問題にも対処しなければいけません。
高精細ディスプレイを搭載したスマートフォンが非常に増えていますが、4 ~ 5 インチ程度の小さな端末に、PCモニターと同程度のピクセルが埋め込まれています。
iPhoneで有名なRetinaディスプレイですが、Retinaは『網膜』を意味する言葉で、肉眼では識別できないほど1つのピクセル(画素)が小さいと言われています。
このような極小ピクセルでにおいて従来通りの処理で表示すれば、コンテンツが小さ過ぎて見えにくくなってしまいますね。
そこで、異なるサイズや解像度のデバイスであっても同じ大きさで表示できるようにする考えられた仕組みが density (ピクセル密度) です。
desity によって『1pxのデータを表示するのに使う物理的なピクセル数』が決まります。
デバイスピクセル比 (Device Pixel Ratio) とも言われ、値を比率で示します。
例えば、iPhone 8 のRetinaディスプレイは、画像の1pxを描画するのに 2 x 2 = 4px を使って1pxとして処理しているので、デバイスピクセル比(density)は 2 となります。
いわば、画像を引き伸ばしているようなイメージです。
これがスマホの画像がぼやけてしまう原因です。
物理的なドット数の割り当てを増やしているために、画像が粗く表示されるというわけです。
この問題を解決するには、1.5倍、2倍、3倍といった大きさ違いの複製画像を用意して、デバイスピクセル比に応じて画像を出し分ける必要があります。
表示サイズ (CSSピクセル) × デバイスピクセル比 (density) = 画像サイズ
300×300px の画像をデバイスピクセル比 2 の端末でキレイに表示したいなら、600×600px の画像を用意する、といった要領です。
機種ごとのデバイスピクセル比はあらかじめ決まっていて、iPhone x では 3、Android端末にいたっては比率が 4 の機種もあり、どんどん高解像度化しています。
PCにも高解像度ディスプレイは増えてきていますね。
レスポンシブ画像切り替えの3つの方法
画像のレスポンシブ対応は、大きく分けて2つの対策が必要です。
- デバイス解像度に応じてサイズ違いの画像を出し分ける
- 閲覧デバイスに適した内容の画像に切り替える
現在は、HTMLとCSSのネイティブな機能だけで全て対応することができます。
解像度 (サイズ) 違いの画像切り替え
デバイスの解像度や表示サイズに応じて画像を切り替えるには、img要素で srcset属性を利用します。
候補となる複数の画像を用意しますが、最も適切な画像1つのみをブラウザが判断して読み込むので、不要な画像はロードされません。
srcset と一緒に使える機能に sizes 属性があります。
sizes では、メディアクエリを使ってビューポート幅(ブラウザ幅)に応じた画像の表示サイズを変更できます。
<img sizes="(min-width: 960px) 75vw, 100vw" srcset="img-1440.png 1440w, img-720.png 720w, img-360.png 360w" src="default-image.png">
JavaScriptを使うことなく、HTMLの記述だけで画像ファイルを切り替えられるので、もはやレスポンシブイメージの実装に不可欠な機能です。
→ srcset と sizes 属性 解説ページへ
デバイス (ブラウザ幅) ごとの画像切り替え
srcset が解像度の違う複製画像を切り替えるのに対し、内容の異なる画像を切り替えるのに利用するのが picture 要素です。
例えば、PC用の画像をそのまま縮小してもモバイル端末では内容がわかりづらいため、「モバイルにはモバイル用の画像を表示させたい」と言ったことはよくありますね。
<picture>
<source media="(min-width: 960px)" srcset="img-pc.jpg">
<img src="img-sp.jpg">
</picture>
srcset による切り替えも併用できるので、より柔軟なレスポンシブイメージを実装することができます。
その他、フォーマット(拡張子)の違う画像を切り替えることもできます。
→ pictureタグ 解説ページヘ
背景画像のレスポンシブ対応
従来通り、背景画像はCSSの background-image を使います。
併せて background プロパティを使えば、レスポンシブな表示の調整が行えます。
また、メディアクエリ resolution と -webkit-device-pixel-ratio を利用すれば、背景画像を高解像度ディスプレイに対応させることもできます。
@media only screen and (-webkit-min-device-pixel-ratio: 2) and (max-width: 959px), only screen and (min-resolution: 192dpi) and (max-width: 959px) {
.header {
background-image: url("images/bg-sp-2x.jpg");
background-size: cover;
background-position: 50% 0;
}
}
→ CSSの背景画像のレスポンシブ対応 解説ページへ
picturefill.jsで未対応ブラウザへの対策
picture と srcset は多くのブラウザが対応していますが、Internet Explorer (IE) の全てのバージョンが未対応です。
残念ながらIEブラウザのシェアは、2018年現在でも15%近くもあります。
picture も srcset も、未対応ブラウザでは <img src="…">
のリソースにフォールバックされて画像が読み込まれるので、そのまま利用しても大きな問題はありません。
しかし IE においても他のブラウザと同等の画像切り替えを提供したいならば、Picturefill と言う JavaScript を利用する方法があります。
2018年6月時点での安定版は 3.0.2 となっています。
picuturefill.min.js の方のファイルをダウンロードまたはコピーして保存し、サーバーにファイルをアップしておきます。CDNも利用できます。
headタグ内にコードを記述します。
<head>
<script>document.createElement( "picture" );</script>
<script src="picturefill.js" async></script>
</head>
HTML5未対応ブラウザ対策のために html5shiv を別途読み込んでいる場合は、1行目のスクリプトは不要で、picturefillを読み込むだけOKです。
<head>
<script src="picturefill.js" async></script>
</head>
これだけで srcset や picture を古いブラウザでも機能させることができます。
picturefillが不要になったら、ファイルと上記のコードを削除するだけなので、メンテナンスも簡単です。
デバイス解像度に依存しないSVG画像
もう1つ、忘れてはいけないのは、SVG (Scalable Vector Graphics) の利用です。
SVGは拡大しても画質が粗くならないので、デバイス解像度や表示サイズによる画像の切り替え自体が不要になります。
Internet Explorer 8 以下と Android 2.x の古いブラウザは未対応ですが、充分実用レベルにあります。
HTMLの img 要素やCSSの background-image など通常の画像と同じように読み込める他、svg要素を使ってテキストベースで記述(インラインSVG)することもできます。
SVG画像の作成は、Adobe イラストレーターなどのドローイングソフトを利用して書き出すのが最も簡単でしょう。
ロゴ・アイコン・イラストといった類の画像に向いています。
XML言語ベースなので、ファイルサイズが小さくなるメリットもあります。
img要素の記述例
<img src="images/twitter-icon.svg" alt="Twitter">
インラインSVGの記述例
<svg id="Logo_FIXED" data-name="Logo — FIXED" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 400 400"><defs><style>.cls-1{fill:none;}.cls-2{fill:#1da1f2;}</style></defs><title>Twitter_Logo_Blue</title><rect class="cls-1" width="400" height="400"/><path class="cls-2" d="M153.62,301.59c94.34,0,145.94-78.16,145.94-145.94,0-2.22,0-4.43-.15-6.63A104.36,104.36,0,0,0,325,122.47a102.38,102.38,0,0,1-29.46,8.07,51.47,51.47,0,0,0,22.55-28.37,102.79,102.79,0,0,1-32.57,12.45,51.34,51.34,0,0,0-87.41,46.78A145.62,145.62,0,0,1,92.4,107.81a51.33,51.33,0,0,0,15.88,68.47A50.91,50.91,0,0,1,85,169.86c0,.21,0,.43,0,.65a51.31,51.31,0,0,0,41.15,50.28,51.21,51.21,0,0,1-23.16.88,51.35,51.35,0,0,0,47.92,35.62,102.92,102.92,0,0,1-63.7,22A104.41,104.41,0,0,1,75,278.55a145.21,145.21,0,0,0,78.62,23"/></svg>
CSSの記述例.bg {
background-image: url("images/bg-image.svg");
}
まとめ
- 従来のJavaScriptやCSSによるHTML画像の切り替えはパフォーマンスを落とす
- 高解像度ディスプレイを想定した画像の切り替えも必要
- srcset と picture を使えばHTMLだけで画像切り替えができる
- SVG画像は解像度に依存せずにキレイに表示できてファイルサイズも軽量
- 背景画像では resolution と -webkit-device-pixel-ratio メディアクエリを使えば高解像度ディスプレイに対応できる
以上が、レスポンシブな画像切り替えの新常識です。
コメントをどうぞ