sizes="auto"で終わるレスポンシブ画像の手計算 — Safari 27で3ブラウザ完結
ktkt約10分で読めます

sizes="auto"で終わるレスポンシブ画像の手計算 — Safari 27で3ブラウザ完結

技術メモ

レスポンシブ画像の srcset と sizes は、理屈は単純なのに手書きすると途端に面倒になります。ブレークポイントごとに「この幅のとき画像は何pxで表示されるか」を先に宣言しなければならず、sizes="(max-width: 640px) 100vw, (max-width: 1024px) 50vw, 33vw" のような文字列をCSSのレイアウトと二重管理することになります。書き間違えるとブラウザは想定より大きな画像を掴んだり、逆に小さすぎる画像を引き伸ばしたりします。前者は転送量の無駄、後者は画質劣化、そしてどちらも LCP(Largest Contentful Paint)の悪化 につながります。Safari 27では、この手計算から解放される sizes="auto" に対応しました。この記事では従来の書き方との対比、遅延読み込みと組み合わせる理由、3ブラウザの対応状況、Next.jsでの運用までを整理します。

Before: sizes手計算のつらさ

従来の sizes は、いわばブラウザへの「事前申告」です。画像の読み込み時点ではCSSレイアウトがまだ確定していないことが多いため、ブラウザは sizes の宣言だけを頼りに「この画像は最終的に何pxで表示されそうか」を推測し、srcset の候補から1枚を選びます。宣言がレイアウトと食い違うと、最適な候補を選べません。たとえば2カラムの記事一覧では、モバイルで1カラム(100vw)、タブレットで2カラム(50vw)、PCで3カラム(33vw)といった具合に、ブレークポイントごとの表示幅を全部書き下す必要がありました。

HTML
<img
  src="thumb-800.jpg"
  srcset="thumb-400.jpg 400w, thumb-800.jpg 800w, thumb-1200.jpg 1200w"
  sizes="(max-width: 640px) 100vw, (max-width: 1024px) 50vw, 33vw"
  loading="lazy"
  decoding="async"
  width="800"
  height="450"
  alt="記事サムネイル" />

この書き方の問題は3つあります。第一に、CSSの grid-template-columns やコンテナの max-width を変えるたびに sizes も直さなければならず、二重管理になります。第二に、カードの余白(gap)やpaddingを引いた実表示幅までは書ききれないので、どうしても概算になります。第三に、コピー&ペーストで別ページに流用したときに古いブレークポイントが残り、誰も気づかないまま過大な画像を読み続ける事故が起きます。実案件では「PCでは3カラムなのに sizes が 100vw のまま」で、毎回1200w級の画像を12枚読んでいた事例もありました。転送量が増えるだけでなく、帯域の細いモバイル回線ではLCPが素直に悪化します。

既存サイトの sizes が正しいかは、DevToolsのNetworkパネルで画像の転送サイズと、Elementsパネルで測った実表示幅を比べると分かります。実表示幅の2倍(DPR 2x相当)を超える候補ばかり選ばれていたら、sizes の宣言が実レイアウトより大きく見積もられています。

After: loading=lazy + sizes=auto

sizes="auto" は、この「事前申告」をやめて「実測」に切り替える指定です。仕組みの鍵は loading="lazy" との組み合わせにあります。通常の(eagerな)画像は、レイアウトが確定する前にプリロードスキャナが先読みするため、ブラウザは sizes の宣言なしには候補を選べません。一方、遅延読み込みの画像はすぐには取得されず、スクロールが近づいてレイアウトが確定してから読み込みが始まります。その時点では「この img が実際に何pxで表示されるか」が分かっているので、ブラウザが自分で実測して srcset から最適な1枚を選べます。これが sizes="auto" のタイミングの理屈です。開発者がブレークポイントを列挙しなくても、コンテナの幅・gap・paddingを反映した正確な選択ができます。

HTML
<!-- 遅延読み込みの画像は sizes="auto" に置き換えられる -->
<img
  src="thumb-800.jpg"
  srcset="thumb-400.jpg 400w, thumb-800.jpg 800w, thumb-1200.jpg 1200w"
  sizes="auto"
  loading="lazy"
  decoding="async"
  width="800"
  height="450"
  alt="記事サムネイル" />

<!-- ヒーロー画像など即時表示が必要な画像には使えない -->
<img
  src="hero-1600.jpg"
  srcset="hero-800.jpg 800w, hero-1600.jpg 1600w, hero-2400.jpg 2400w"
  sizes="100vw"
  fetchpriority="high"
  decoding="async"
  width="1600"
  height="900"
  alt="ヒーロー画像" />

重要な注意点として、sizes="auto" は loading="lazy" とセットで使います。ヒーロー画像やファーストビューのメインビジュアルのような非遅延(eager)の画像では、レイアウト確定を待っていては読み込み開始が遅れ、かえってLCPを悪化させます。仕様上も auto は遅延読み込み画像向けであり、eagerな画像に付けても自動計算は働きません。使い分けはシンプルです。ファーストビューの1枚は手書きの sizes と fetchpriority="high" で最速化し、スクロール先の一覧画像・本文内画像は loading="lazy" + sizes="auto" で正確化する。この二段構えが現時点の正解です。また width / height 属性は auto の有無にかかわらず必ず付けます。読み込み前のレイアウトシフト(CLS)防止と、実測選択の基準になるためです。

decoding="async" と loading="lazy" は何が違うの?→ loading="lazy" は「いつ取得するか」(視界に近づくまで待つ)の指定で、decoding="async" は「取得後にいつ復号するか」(メインスレッドを塞がず裏で復号)の指定です。sizes="auto" の実測に効くのは前者のタイミングです。両者は併用できます。

Chromeではどうなの?

この機能自体は新しくありません。Chromeでは2年前から実装されており、現場ではすでに常識として使われています。Safari 27でSafariが追いついたことで、ようやく「3ブラウザ全部で使える」状態になりました。対応状況は次の通りです。

ブラウザ

sizes="auto" の対応

備考

Chrome / Edge

126以降で対応

2024年から利用可能。現場の標準

Firefox

150以降で対応

遅延読み込み画像の自動選択に対応

Safari

27で対応

リリースノートに記載あり。caniuseは2026年8月時点で未更新のためSafari Technology Previewでの実測推奨

最新の対応状況は caniuse: sizes="auto" で確認できます。注意点として、caniuse側のSafari欄は2026年8月時点ではまだ未更新のため、緑になっていなくても悲観する必要はありません。一次情報であるSafari 27のリリースノートには対応が明記されており、Safari Technology Previewでの実測でも動作が確認できます。結論は明快です。Chromeでは2年前から常識だったものに、Safariが追いついて全面解禁になった。これからは「lazy画像には auto を付ける」を既定値にして問題ありません。

LCPとの関係も整理しておきます。sizes="auto" は万能ではなく、適用先によって役割が分かれます。

画像の種類

推奨指定

理由

ヒーロー画像(LCP要素)

手書きsizes + eager + fetchpriority="high"

先読みで最速開始。autoは待機が発生し逆効果

一覧・本文内のlazy画像

sizes="auto" + loading="lazy"

実測で最適候補を選択。転送量削減

アイコン・装飾の小画像

srcset自体が不要なことも多い

候補を増やすより1枚+CSS指定が軽い

ヒーロー画像かどうかの判定は、Lighthouseの「LCP element」表示か、WebPageTestのフィルムストリップで確認します。ファーストビューで最大面積になる画像だけをeager+手書きsizesにし、それ以外は迷わず sizes="auto" に寄せるのが安全です。

Next.jsでの運用

Next.jsの next/image を使っている場合も、考え方は同じです。next/image は sizes プロパティを渡す設計になっており、最終的に出力される img タグの sizes 属性に反映されます。つまり「ブレークポイントごとの表示幅を宣言する」という発想自体は変わりません。遅延読み込みの一覧画像では sizes に実レイアウトに合う値を渡し、ファーストビューの画像は優先読み込み側に倒す、という使い分けが基本になります。

運用上のコツは、sizes の値をページごとに場当たり的に書くのではなく、グリッドの列数と連動させて定数化することです。たとえば「記事一覧はモバイル1列・タブレット2列・PC3列」というレイアウトが決まっているなら、その対応表を1か所にまとめ、全カードで同じ値を参照します。こうしておけば、将来グリッドを4列に変えたときの修正箇所が1か所で済み、Before節で触れた「古いブレークポイントの残置」事故を防げます。断定的なAPI仕様の話はここでは踏み込みませんが、どのバージョンでも「出力されるHTMLの sizes が実レイアウトと一致しているか」をDevToolsで確かめる習慣が有効です。最適化コンポーネントを使っていても、最終的にブラウザが見るのはただの img タグだからです。

HTML
<!-- next/image の出力をDevToolsで見たときの目安(概念図) -->
<!-- 一覧カード: 遅延読み込みなので auto で実測に任せる -->
<img srcset="card-400.jpg 400w, card-800.jpg 800w, card-1200.jpg 1200w"
  sizes="auto" loading="lazy" decoding="async"
  width="800" height="450" alt="記事カード" />
<!-- ヒーロー: 先読みするので表示幅を明示する -->
<img srcset="hero-800.jpg 800w, hero-1600.jpg 1600w"
  sizes="100vw" fetchpriority="high" decoding="async"
  width="1600" height="900" alt="ヒーロー" />

まとめ

手書きの sizes はレイアウトとの二重管理であり、書き間違えは転送量とLCPに直結します。遅延読み込みの画像は sizes="auto" に置き換え、実測選択に任せるのが安全です。ヒーロー画像だけは手書き sizes とeagerのまま残し、Safari 27以降の3ブラウザでこの二段構えを標準にしましょう。

参考リンク

SERIES

Safari 27の新機能を実装で確認

Safari 27で使えるようになったCSS・アクセシビリティ・画像最適化の機能を、コードとフォールバックつきで確認する特集です。Chromeとの対応差がある機能は、無理に全面採用せず「使う場面」を限定して紹介しています。

シリーズの記事を読む(4本)
シェア
ktkt
ktkt運営者

フルスタックWebエンジニア。モダンなフロントエンドとAPI開発が得意。 Next.jsを中心にWebアプリ制作、AI活用支援、動画編集など活動中。 複雑な技術を、使える道具にデコードする。

タグで探す

関連記事

同じタグ・カテゴリの記事から選んでいます。