img要素にあるsizes属性の変わった使い方(sizesに画素密度メディアクエリを使う)
img要素に sizes属性というものがあります。
この属性は srcset属性とセットで使われ、画像選択の際に、読み込む画像の条件を指定することができる属性です。
文字で書いたら何だか分かりにくいですよね。サンプルを見ながら解説します。
srcset属性と sizes属性
知らない方のために srcset 属性と sizes 属性について簡単に説明します。
「説明します」と言ってますが、わたしも他のサイトを参考に勉強したんですけどね(笑)
srcset属性
srcset 属性は複数の画像を条件によって分けて読み込ませることができる属性です。
例えば画面サイズが300ピクセルならAの画像、600ピクセルならBの画像と、画面や要素の大きさで読み込む画像を選別できるのです。
このブログでも記事タイトル下の画像などでは、この属性を使っています。
<img src="https://女性の画像.jpg"
srcset="https://猫の画像.jpg 500w,
https://犬の画像.jpg 800w"
alt="サンプル画像">
ちなみに対応していないブラウザでは、タイトル下と同じ女性の画像が表示されます。見ての通り画像は全部ぱくたそさんのものを使わしていただいてます。
またAMPでは全て猫です。
指定方法は画像URLをカンマ(,
)で区切り、URL後方に半角スペースで開けて切り替える基準値を指定します。
上記のコードでは表示領域の幅が500画素以下なら猫の画像、800画素以下およびそれ以上なら犬の画像が表示されます。
指定できる単位は" w "が付いている幅を指定できる単位(幅記述子)が使えます。
あと 1x、2xなど、" x "を使って画素密度による切り替えもできす。Retinaディスプレイなど高画素密度なら犬、そうでないときは猫です。
<img src="https://女性の画像.jpg"
srcset="https://猫の画像.jpg 1x,
https://犬の画像.jpg 2x"
alt="サンプル画像">
sizes属性
ただ上記の srcset属性は画素数で読み込む画像を選別します。
これがどういうことかと言えば、iPhoneなどでは指定した幅値の半分程度のピクセル値で切り替わってしまうのです。
もし指定数値が 600w ならば、iPhoneの画面では300ピクセル程度の幅で読み込む画像が切り替わります。
つまり画素数で計算するので1ピクセルの幅に2つの画素を持つ Retinaディスプレイならば、単純に半分のピクセル値で指定した画素数になるのです。
これを回避する方法として使えるのが sizes 属性です。sizes属性は srcset属性が無いと使えない属性で、例えばsizes="50vw"
と指定すると、画像は画面の半分の大きさに縮小されて表示されます。
<img src="https://女性の画像.jpg"
sizes="50vw"
srcset="https://猫の画像.jpg 500w,
https://犬の画像.jpg 800w"
alt="サンプル画像">
表示されるサイズが画面の半分になるという指定があるため、選択される画素数の幅が2倍になります。つまり Retinaディスプレイで 500px = 500w と従来のディスプレイと同じように画像が選択されるのです。
そのかわり表示される画像は半分の大きさですが、これは CSS で調整できます。
さらに srcset属性ではメディアクエリも指定できるのです。次のコードは415ピクセル以下では画面の半分で表示し、それ以上なら原寸大(100vw)で表示します。
<img src="https://女性の画像.jpg"
sizes="( max-width: 415px ) 50vw, 100vw"
srcset="https://猫の画像.jpg 500w,
https://犬の画像.jpg 800w"
alt="サンプル画像">
この属性の利点は、画像を複数読み込まなくてもすむ所です。その状態によって画像URLを一つ選択してダウンロードするのでページの読み込み速度の向上が期待できます。
ただ、全てのブラウザに対応している訳ではありません。IE11 や古い Android では機能しません。
リンク:Can I use... Support tables for HTML5, CSS3, etc
これら属性に関する詳しいことは、こちらにも書かれているのでぜひ参考にしてください。
参考リンク:<img>: 埋め込み画像要素 - HTML: HyperText Markup Language | MDN
sizes属性のメディアクエリでピクセル比による分岐をする
さて、ここからが本題なのですが、sizes 属性にメディアクエリが使えるのなら、-webkit-min-device-pixel-ratio といったピクセル比で条件分岐できるはずです。
どうしてこれを考えたかというと、Flickr の画像をできるだけ早く読み込ませるためでした。
Flickr は埋め込み用のスクリプトで画像サイズの調整をしてくれるとはいえ、それが機能しないページ読み込み初期の段階では重い画像をダウンロードしていることもあります。
これはスマホなどではよろしくありません。画像が圧縮されてないから、なおさらです。
適切な大きさの画像を読み込むことでページ表示も早くなると考えたのですが、問題は Retina ディスプレイと従来のディスプレイとの関係。あちらを立てればこちらが立たずでなかなか上手くいきません。
なんだかんだ考えたあげく面倒くさくなり、これでいいやと思いついたのが Retinaディスプレイでも従来のディスプレイと同じピクセル値で選別できるようにする設定です。
前置きが長くなりましたが、そうしてできたそのコードがこちらです。
<img src="https://女性の画像.jpg"
sizes="( -webkit-min-device-pixel-ratio: 2 ) 50vw,
( min-resolution: 2dppx ) 50vw,
100vw"
srcset="https://猫の画像.jpg 415w,
https://犬の画像.jpg 736w"
alt="サンプル画像" width="736">
メディアクエリのメディア特性には画素密度を判定するものを入れています。現時点()では iPhone の Safari と Android は -webkit-min-device-pixel-ratio に対応しています。
もう1つの min-resolution は 同じ画素密度を判定するもので、Firefox 対応と将来的に有効だと言わてているため入れています。
数値は 2 より 1.5 のほうが良いそうですが、ここは悩みどころで、50vw
を指定しているのピクセル比が倍の2
にしました。
※この Retinaディスプレイ対応はとても難しいですね。こちらの記事が非常に参考になりました。
参考リンク:いまさら聞けないRetina対応のための「ピクセル」の話 | Rriver
これにより、高密度の Retinaディスプレイでも従来のディスプレイと同じように画像の選別ができるようになりました。
しかしこの方法、他で活躍する場があるのでしょうか? ちょっと分かりません(笑)
まとめ
役に立つかどうかは分かりませんが、これを作るにあたりいろいろ勉強になりました。
また今回この記事を作るときでも、ちゃんと調べ検証しながら書いててので意外と時間がかかりましたが、いろいろ理解が深まって楽しかったです。
役に立うかどうかは分かりませんが、こんなんもあるんだな~と感じていただけたら幸いです。