HTMLImageElement: sizes プロパティ
Baseline
広く利用可能
この機能は広く実装されており、多くのバージョンの端末やブラウザーで動作します。2016年3月以降、すべてのブラウザーで利用可能です。
sizes は HTMLImageElement インターフェイスのプロパティで、画像のレイアウト上の幅を指定できます。メディアクエリーのリストの各項目ごとに指定できるほか、遅延読み込みされる画像に対しては auto を指定することで、要素のレイアウトサイズに基づいてブラウザーが自動的に表示させる画像を選択することができるようにします。
これにより、ブラウザーは要素の srcset で指定されたさまざまな画像の中から、さまざまなメディア条件に一致するものを選べます。方向やアスペクト比が異なる画像であっても同様です。
sizes プロパティは、<img> 要素の sizes コンテンツ属性を反映します。
これは、srcset で幅記述子が使用されている場合にのみ存在します。
値
auto キーワード(任意で、その後に任意の数のソースサイズが続く場合もある)か、1つ以上のソースサイズからなる文字列です。
詳細については、HTML の <img> リファレンスの sizes 属性を参照してください。
例
>ウィンドウの幅に合わせて画像を選択
この例では、ブラウザーが sizes 属性を使用して、画像を現在のビューポート幅における画像のレンダリング幅に基づいて srcset から選択する仕組みを示しています。
同時に、ブラウザーウィンドウのサイズを変更した際に、どの画像が読み込まれるかという効果を確認することもできます。
HTML
遅延読み込みの効果を実証するためには、画像を当初は視覚的ビューポートから非表示にし、その後スクロールして表示領域内に表示させる必要があります。
これは、spacer および demo-wrap コンテナーを含む外側の scroll-container の <div> を使用することで実現されます。
画像は demo-wrap コンテナー内に含まれており、spacer コンテナーに設定された高さによって、このコンテナーが視覚的ビューポートの外側に押し出されます。
この <img> 要素には以下の属性があります。
srcsetでは 4 つの画像が定義しており、それらの幅が600px、900px、1200px、1500pxであることを示しています。srcは、srcsetが対応していない場合や構文解析できない場合に使用する画像を指定します。srcsetの中で最も大きな画像を使用します。これは、最も小さな画像を拡大するよりも、大きな画像を縮小する方が、常に良好な結果が得られるためです。loadingはlazyです。sizesは、ビューポート幅の各ブレイクポイントにおける画像の想定レンダリング幅を指定し、これによりブラウザーがsrcsetから最適な画像を選択することができるようになります。
<div id="scroll-container">
画像を表示するには上にスクロールしてください
<div id="spacer"></div>
<div id="demo-wrap">
<div class="img-container" id="resizable">
<div class="img-square">
<img
loading="lazy"
sizes="(max-width: 600px) 600px, (max-width: 900px) 900px, (max-width: 1200px) 1200px, 1500px"
src="1500.png"
srcset="600.png 600w, 900.png 900w, 1200.png 1200w, 1500.png 1500w"
alt="画像の例" />
</div>
<div class="label">
<strong>コンテナー幅: <span id="width-label"></span></strong>
</div>
</div>
</div>
</div>
CSS と JavaScript は非表示です(これらを確認したい場合は、「再生」を選択して、対話型プレイグラウンドでサンプル全体を表示してください)。
結果
この例は別ウィンドウで開くのがいいでしょう。そうすれば、サイズを自由に調整でき、例が親フレームの制約を受けることもありません。
-
フレームをスクロールして画像を表示させてください。 画像の下部にあるラベルには、現在のコンテナーの幅が示されています。
-
ウィンドウのサイズを変更してみてください。
sizes属性のメディアクエリーのブレイクポイントで、画像が変化するのが確認できるはずです。選択した画像は、コンテナーの幅だけから推測されるよりも大きい場合があることに注意してください。 多くのディスプレイ(おそらく大半)は、デバイスピクセル比 (DPR) が 1 より大きくなっています。 ディスプレイの物理ピクセル密度で鮮明な画像を表示するために、ブラウザーは、
srcsetから選択を行う前に、一致したsizesヒントに DPR を乗算します。 例えば、ビューポートが 2× で 500px 以下のディスプレイの場合、一致するヒントは600pxですが、ブラウザーは 1200px 以下の画像を見ていき、利用できるサイズの中で最も近い1200.pngを選択し、利用可能な空間に収まるように拡縮します。メモ: その結果、特定のブレイクポイントにおいて、特定のディスプレイでは
srcsetに指定された画像の一部にアクセスできない場合があり、これはブラウザーによって異なる可能性があります。
このログには、画像に対して load イベントが発生したタイミングや、画像が表示領域と交差したタイミングに関する情報が記録されます。
なお、画像は遅延読み込みされるため、load イベントは、画像がビューポートに入る直前に発生するはずです。
遅延読み込みされる画像の自動選択
この例では、<img> 要素が遅延読み込みされる際、sizes の値を auto に設定すると、srcset から読み込む画像の選択にどのような影響があるかを示しています。
同時に、コンテナーのサイズを変更した際に、読み込まれた画像にどのような効果が出るかを確認することもできます。
HTML
HTML は前回の例と似ていますが、3 つのほぼ同一の <img> 要素が定義されている点が異なります。それぞれの要素には、幅が 600px、400px、200px の 3 つの画像を示す srcset 属性があり、sizes の値は auto となっています。
これらは、さまざまな画像を選択できるようにサイズが調整されたコンテナー内に収められています。
<div id="scroll-container">
画像を表示するには上にスクロールしてください
<div id="spacer"></div>
<div id="demo-wrap">
<div class="img-container img-container--sm" id="resizable">
<div class="img-square">
<img
loading="lazy"
sizes="auto"
src="600.png"
srcset="600.png 600w, 400.png 400w, 200.png 200w"
alt="小さなコンテナーの画像" />
</div>
<div class="label"><strong>コンテナー幅: 100px</strong></div>
</div>
<div class="img-container img-container--md">
<div class="img-square">
<img
loading="lazy"
sizes="auto"
src="600.png"
srcset="600.png 600w, 400.png 400w, 200.png 200w"
alt="中くらいのコンテナーの画像" />
</div>
<div class="label"><strong>コンテナー幅: 200px</strong></div>
</div>
<div class="img-container img-container--lg">
<div class="img-square">
<img
loading="lazy"
sizes="auto"
src="600.png"
srcset="600.png 600w, 400.png 400w, 200.png 200w"
alt="大きなコンテナーの画像" />
</div>
<div class="label"><strong>コンテナー幅: 400px</strong></div>
</div>
</div>
</div>
CSS
ここでは、さまざまな画像コンテナーのサイズを設定する CSS クラスを示します。
.img-container--sm {
width: 100px;
}
.img-container--md {
width: 200px;
}
.img-container--lg {
width: 400px;
}
残りの CSS や、スライダーやログ出力などを制御する JavaScript は表示していません(これらを確認したい場合は、「再生」を選択して、対話的プレイグラウンドでサンプル全体をご覧ください)。
結果
フレームをスクロールして、3 つの画像を表示してください。 ブラウザーは、幅の制約の違いに基づいて、それぞれの画像を選択しているはずです。 スライダーを使って、最初の画像のコンテナーのサイズを変更することができます。 なお、コンテナーのサイズが変化しても、ブラウザーが新しい画像を選択して表示するかどうかは実装次第であり、動的な変化に反応することが必須ではないため、必ずしも新しい画像が表示されるとは限りません。
このログには、それぞれの画像に対して load イベントが発生したタイミングや、画像が可視ビューポートと重なるタイミングに関する情報が記録されます。
なお、画像は遅延読み込みされるため、load イベントは画像がビューポートに入る直前に発生するはずです。
また、最初の画像のコンテナーサイズを変更した際にも load イベントが発生しますが、これはブラウザーがレイアウトを再計算したことを示すものであり(必ずしも新しい画像が読み込まれたことを意味するわけではありません)、この点にもご注意ください。
ブログの例
ソースサイズを使用してウィンドウの幅に合わせて画像を選択する方法を示す、もう少し実用的な例を示します。
この例では、ブログ風のレイアウトを作成し、テキストと画像を表示します。画像は、ウィンドウの幅に応じて 3 つのサイズポイントが指定されています。 画像も 3 種類用意し、それぞれの幅を指定しています。ブラウザーはこれらの情報をすべて受け取り、指定された値に最も合う画像と幅を選択します。
画像がどのように使われるかは、ブラウザーやユーザーのディスプレイの画素密度に依存する場合があります。
この例の下にあるボタンで、実際に sizes プロパティを少し変更し、画像の 3 つの幅のうち最大のものを 40em と 50em の間で切り替えています。
HTML
<article>
<h1>素晴らしい見出し</h1>
<div class="test"></div>
<p>
これはさらにすごいコンテンツテキストです。実に見事です。そして、とても魅力的です。ああ、同時に賢く、ユーモアもあります。間違いなく受賞作級の出来ですね。
</p>
<img
src="new-york-skyline-wide.jpg"
srcset="
new-york-skyline-wide.jpg 3724w,
new-york-skyline-4by3.jpg 1961w,
new-york-skyline-tall.jpg 1060w
"
sizes="(50em <= width <= 60em) 50em,
(40em <= width < 50em) 30em,
(width < 40em) 20em"
alt="晴れた日のニューヨークのスカイライン。中央には新しいワン・ワールド・トレード・センターがついている。" />
<p>
それから、ここにはまだすごい話があります。信じられる?僕は到底信じられないよ。
</p>
<button id="break40">最終的な幅: 40em</button>
<button id="break50">最終的な幅: 50em</button>
</article>
CSS
article {
margin: 1em;
max-width: 60em;
min-width: 20em;
border: 4em solid #880e4f;
border-radius: 7em;
padding: 1.5em;
font:
16px "Open Sans",
"Verdana",
"Helvetica",
"Arial",
sans-serif;
}
article img {
display: block;
max-width: 100%;
border: 1px solid #888888;
box-shadow: 0 0.5em 0.3em #888888;
margin-bottom: 1.25em;
}
JavaScript
JavaScript のコードでは、3 つ目の幅のオプションを 40em と 50em の間で切り替えることができる 2 つのボタンを処理しています。これは click イベントを処理することで、 JavaScript 文字列オブジェクトの replace() メソッドを使って sizes 文字列の該当部分を置換して実現しています。
const image = document.querySelector("article img");
const break40 = document.getElementById("break40");
const break50 = document.getElementById("break50");
break40.addEventListener(
"click",
() => (image.sizes = image.sizes.replace(/50em,/, "40em,")),
);
break50.addEventListener(
"click",
() => (image.sizes = image.sizes.replace(/40em,/, "50em,")),
);
結果
このページは独自のウィンドウで見るほうが、大きさを完全に調整できるので適しています。
- 開発者ツールを有効にして、ページの幅を変更してみてください。メディアクエリーのブレークポイントである
640px(40em) および800px(50em) で、画像が変化し(サイズが跳ね上がる)、確認できるはずです。 - 最後のメディアクエリーが適用されるように、幅を
50em(800px)から60em(960px) の間に設定してください。 次に、それぞれのボタンを順番に押してみて、画像のレイアウトサイズがどのように変化するかを確認してください。メモを取ってください。
仕様書
| 仕様書 |
|---|
| HTML> # dom-img-sizes> |