- 技術 💻
srcset・sizesの使い方|picture併用とDevToolsでの検証
srcset とは、同じ画像の大きさ違いを複数並べておき、画面幅や画面の細かさ(DPR)に合った1枚をブラウザに選ばせる img 要素の属性です。 sizes は「その画像がページ上で何 px の幅で表示されるか」をブラウザに伝える属性で、srcset と組み合わせて使います。
この記事では、w 記述子・x 記述子と sizes の仕組み、ブラウザが画像を選ぶ計算を整理したうえで、Pillow で幅別の画像を作り、Playwright 1.56.1+Chromium 141 で「画面幅×DPR(1/2/3)ごとに実際にダウンロードされた画像」を記録した一覧を載せます。さらに、sizes を書き忘れたときに大きな画像が読み込まれる様子の再現、picture でのアートディレクションと AVIF/WebP の切り替え、sizes="auto" と loading="lazy" の関係、LCP 画像の書き方、DevTools と WordPress での確認方法までまとめます。
srcset・sizes の早見表
まずはこの表で、目的に合う書き方を選べます。
| やりたいこと | 書き方 | 選ばれ方 |
|---|---|---|
| 表示幅が固定の画像(ロゴ・アイコン)を高精細にする | srcset="a.jpg 1x, a@2x.jpg 2x" |
DPR に合う x の値 |
| 表示幅が画面で変わる画像 | srcset="a-640.jpg 640w, a-1280.jpg 1280w" sizes="..." |
表示幅 × DPR 以上の最小の w |
| 常に画面いっぱいの画像 | sizes="100vw" |
画面幅 × DPR |
| PC は2列、スマホは1列 | sizes="(min-width: 1024px) 50vw, 100vw" |
条件に合った最初の値 |
| 最大幅のあるコンテナ内 | sizes="(min-width: 1200px) 1140px, 95vw" |
上限の px を明記 |
| 遅延読み込みの画像で sizes を自動にする | loading="lazy" sizes="auto, 100vw" |
実際のレイアウト幅 |
| スマホとPCで画像の切り抜きを変える | <picture><source media="..."> |
最初に条件が合う source |
| AVIF → WebP → JPEG の順に出し分ける | <source type="image/avif"> を先に書く |
対応している最初の形式 |
| 最初に見える大きな画像(LCP)を速く出す | fetchpriority="high"、lazy にしない |
優先度が上がる |
| レイアウトのずれを防ぐ | width・height 属性を必ず書く |
縦横比が事前に確保される |
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「srcset・sizesの使い方|picture併用とDevToolsでの検証」
srcset の w 記述子と x 記述子の違い
srcset に並べる各画像には、w 記述子(画像の実際の横幅)か x 記述子(何倍の密度か)のどちらかを付けます。
<!-- x 記述子:表示幅が 400px で固定の画像 -->
<img src="logo-1x.jpg"
srcset="logo-1x.jpg 1x, logo-2x.jpg 2x, logo-3x.jpg 3x"
width="400" height="225" alt="ロゴ">
<!-- w 記述子:表示幅が画面に合わせて変わる画像 -->
<img src="photo-800.jpg"
srcset="photo-480.jpg 480w, photo-800.jpg 800w, photo-1280.jpg 1280w, photo-1600.jpg 1600w"
sizes="(min-width: 1024px) 50vw, 100vw"
width="1600" height="900" alt="サンプル写真">
| 項目 | x 記述子 | w 記述子 |
|---|---|---|
| 書く値 | 密度(1x, 2x, 3x) | 画像ファイルの横幅(px)に w を付けたもの |
| sizes | 不要 | 必要(書かないと 100vw とみなされる) |
| 向いている画像 | ロゴ、アイコン、アバターなど表示幅が一定 | 本文の写真、ヒーロー画像、カード画像など |
| ブラウザの判断材料 | DPR だけ | 表示幅(sizes)と DPR |
| 1つの srcset 内で混在 | できない(どちらか一方に揃える) | できない |
DPR(デバイスピクセル比)とは、CSS の 1px を画面の何ドットで表示するかの値です。 一般的な PC 画面は 1、多くのスマホは 2〜3 です。
ブラウザが画像を選ぶ計算
w 記述子の場合、ブラウザは「sizes で決まる表示幅 × DPR」以上の幅を持つ画像のうち、なるべく小さいものを選びます。 正確には、各画像の密度を「w の値 ÷ 表示幅」で求め、DPR に合う密度の画像を選びます。
1. sizes を上から順に評価し、最初に条件が合った値を表示幅にする
例:画面 1440px、sizes="(min-width: 1024px) 50vw, 100vw" → 720px
2. 各候補の密度 = w ÷ 表示幅
photo-640 → 640 ÷ 720 = 0.89x
photo-800 → 800 ÷ 720 = 1.11x
photo-1600 → 1600 ÷ 720 = 2.22x
3. DPR 以上で最も小さい密度の候補を選ぶ
DPR 1 → photo-800(1.11x)、DPR 2 → photo-1600(2.22x)
仕様上、最終的にどれを選ぶかはブラウザに任されていて、通信状況やキャッシュによって別の候補を使うこともあります。今回の Chromium 141 の計測では、すべての組み合わせでこの「表示幅 × DPR 以上の最小の w」の規則どおりの画像が選ばれました。
sizes の書き方のポイントです。
| 書き方 | 意味 | 注意点 |
|---|---|---|
(min-width: 1024px) 50vw, 100vw |
1024px 以上は画面の半分、それ以外は全幅 | 上から順に評価され、最初に合ったものが使われる |
(min-width: 1200px) 1140px, 95vw |
上限のあるコンテナ | px で上限を書くと大画面での無駄が減る |
calc((100vw - 32px) / 3) |
余白を除いた3等分 | calc() や min() も使える |
% の値 |
使えない | sizes に % は書けない(vw か px で書く) |
| 最後の値 | 条件なしの既定値 | 必ず条件なしで書く |
画面幅×DPRごとに実際にダウンロードされた画像
Pillow 12.2.0 で幅 320〜2400px の画像を9種類作り、ローカルサーバー(Node.js)で配信して、Playwright+Chromium 141.0.7390.37 で読み込みました。 画面幅と DPR の組み合わせごとに新しいブラウザコンテキスト(キャッシュなし)を作り、実際に発生した画像リクエストを記録しています。
画像の生成スクリプトです(Python 3.11、pip install pillow)。
# gen.py
from PIL import Image, ImageDraw
import os
os.makedirs("img/images", exist_ok=True)
def make(w, h, name, fmt="JPEG"):
im = Image.new("RGB", (w, h), (70, 130, 180))
d = ImageDraw.Draw(im)
d.rectangle([w // 10, h // 10, w * 9 // 10, h * 9 // 10], outline=(255, 255, 255), width=max(2, w // 200))
d.text((w // 8, h // 8), f"{w}x{h}", fill=(255, 255, 255))
im.save(f"img/images/{name}", fmt, quality=80)
for w in [320, 480, 640, 800, 1024, 1280, 1600, 1920, 2400]:
make(w, w * 9 // 16, f"photo-{w}.jpg")
for w in [800, 1600]: # 形式切り替えの確認用
make(w, w * 9 // 16, f"item-{w}.avif", "AVIF")
make(w, w * 9 // 16, f"item-{w}.webp", "WEBP")
make(w, w * 9 // 16, f"item-{w}.jpg")
計測した HTML と、計測用スクリプトの要点です。
<style>
img { display: block; max-width: 100%; height: auto; }
.half { width: 100%; }
@media (min-width: 1024px) { .half { width: 50%; } }
</style>
<img id="t" class="half" src="images/photo-800.jpg"
srcset="images/photo-320.jpg 320w, images/photo-480.jpg 480w, images/photo-640.jpg 640w,
images/photo-800.jpg 800w, images/photo-1024.jpg 1024w, images/photo-1280.jpg 1280w,
images/photo-1600.jpg 1600w, images/photo-1920.jpg 1920w, images/photo-2400.jpg 2400w"
sizes="(min-width: 1024px) 50vw, 100vw"
width="1600" height="900" alt="サンプル写真">
// itest.mjs(抜粋) npm i playwright@1.56.1 / node itest.mjs
const ctx = await browser.newContext({ viewport: { width: w, height: 800 }, deviceScaleFactor: dpr });
const page = await ctx.newPage();
const got = [];
page.on('request', (q) => { if (q.resourceType() === 'image') got.push(q.url().split('/').pop()); });
await page.goto(base + 'a.html', { waitUntil: 'load' });
const cur = await page.$eval('#t', (e) => e.currentSrc.split('/').pop());
実行結果(抜粋):
A 375px DPR1 表示幅375px → photo-480.jpg DL:[photo-480.jpg]
A 375px DPR2 表示幅375px → photo-800.jpg DL:[photo-800.jpg]
A 375px DPR3 表示幅375px → photo-1280.jpg DL:[photo-1280.jpg]
A 1440px DPR1 表示幅720px → photo-800.jpg DL:[photo-800.jpg]
A 1440px DPR2 表示幅720px → photo-1600.jpg DL:[photo-1600.jpg]
A 1440px DPR3 表示幅720px → photo-2400.jpg DL:[photo-2400.jpg]
全組み合わせを表にまとめます(セルはダウンロードされたファイル。各組み合わせで画像リクエストは1件だけでした)。
| 画面幅 | 表示幅(sizes) | DPR 1 | DPR 2 | DPR 3 |
|---|---|---|---|---|
| 375px | 375px(100vw) | photo-480 | photo-800 | photo-1280 |
| 768px | 768px(100vw) | photo-800 | photo-1600 | photo-2400 |
| 1024px | 512px(50vw) | photo-640 | photo-1024 | photo-1600 |
| 1440px | 720px(50vw) | photo-800 | photo-1600 | photo-2400 |
| 1920px | 960px(50vw) | photo-1024 | photo-1920 | photo-2400 |
768px の画面(1列表示)のほうが、1024px の画面(2列表示)より大きな画像を読み込んでいます。 画面幅ではなく「表示幅 × DPR」で選ばれるためです。また、1920px・DPR 3 では必要な幅(2880px)を満たす画像がないため、最大の photo-2400 が選ばれました。 候補の最大幅は、想定する最大の「表示幅 × DPR」を目安に決めます。
x 記述子(表示幅 400px 固定)の結果です。
C DPR1 → logo-1x.jpg
C DPR1.5 → logo-2x.jpg
C DPR2 → logo-2x.jpg
C DPR3 → logo-3x.jpg
DPR 1.5 のように中間の値では、それ以上の密度で最も小さい 2x が選ばれました。
sizes を書き忘れると大きすぎる画像が読み込まれる
w 記述子を使っていて sizes を書かないと、ブラウザは表示幅を 100vw(画面幅いっぱい)とみなします。 3列のカード一覧のように、実際の表示幅が画面幅より小さい画像で差が出ます。
<!-- 直す前:sizes なし(3列グリッドの中の画像) -->
<div class="grid">
<img src="images/photo-800.jpg" srcset="images/photo-320.jpg 320w, ...(略)..., images/photo-2400.jpg 2400w"
width="1600" height="900" alt="">
</div>
<!-- 直した後:sizes でグリッドの1列分の幅を伝える -->
<div class="grid">
<img src="images/photo-800.jpg" srcset="images/photo-320.jpg 320w, ...(略)..., images/photo-2400.jpg 2400w"
sizes="(min-width: 768px) min(calc((100vw - 32px) / 3), 309px), 100vw"
width="1600" height="900" alt="">
</div>
<style>
.grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px; max-width: 960px; margin: auto; }
@media (max-width: 767px) { .grid { grid-template-columns: 1fr; } }
</style>
実行結果:
B-なし 1440 DPR1 表示幅309px → photo-1600.jpg DL:[photo-1600.jpg]
B-あり 1440 DPR1 表示幅309px → photo-320.jpg DL:[photo-320.jpg]
B-なし 1440 DPR2 表示幅309px → photo-2400.jpg DL:[photo-2400.jpg]
B-あり 1440 DPR2 表示幅309px → photo-640.jpg DL:[photo-640.jpg]
B-なし 375 DPR2 表示幅375px → photo-800.jpg DL:[photo-800.jpg]
B-あり 375 DPR2 表示幅375px → photo-800.jpg DL:[photo-800.jpg]
| 条件 | sizes なし | 正しい sizes | 読み込む画像の幅の比 |
|---|---|---|---|
| 1440px・DPR 1(表示 309px) | photo-1600 | photo-320 | 5倍 |
| 1440px・DPR 2(表示 309px) | photo-2400 | photo-640 | 3.75倍 |
| 375px・DPR 2(表示 375px) | photo-800 | photo-800 | 同じ |
表示は 309px なのに、sizes なしでは 1600px や 2400px の画像が読み込まれました。 スマホの1列表示では表示幅が画面幅と同じなので差は出ません。PC の画面で確認しないと気づきにくい点です。
sizes の値を間違えやすいパターンと直し方です。
| パターン | 起きること | 直し方 |
|---|---|---|
| sizes を書かない | 100vw とみなされ大きな画像を読む | 実際の表示幅を書く |
全部 100vw にしている |
カード・サイドバーの画像で大きな画像を読む | レイアウトごとの幅を書く |
| 最大幅のあるコンテナなのに vw だけ | 大画面で必要以上に大きな画像を読む | min(95vw, 1140px) や px の上限を書く |
| sizes の条件の順番が逆 | 先に合った条件が使われ、意図しない幅になる | 広い条件(min-width の大きいもの)から書く |
| CSS の表示幅を変えたのに sizes を直していない | 表示と sizes がずれる | CSS と sizes をセットで見直す |
DevTools で選ばれた画像を確かめる方法
ブラウザで確認するときは、Chrome の DevTools を次の手順で使います。(以下の DevTools の操作は画面での確認方法の説明で、本記事の計測は上の Playwright で行っています。)
| 手順 | 操作 | わかること |
|---|---|---|
| 1 | DevTools の Network タブで「Disable cache」にチェックし、種類を「Img」に絞る | 実際にダウンロードされたファイル |
| 2 | デバイスツールバー(端末アイコン)で幅と DPR を指定して再読み込み | 画面幅・DPR ごとの選ばれ方 |
| 3 | Elements タブで img にマウスを乗せる | 表示サイズ(Rendered size)と画像の元サイズ(Intrinsic size)、選ばれた画像(Current source) |
| 4 | img を選択して Console で $0.currentSrc |
選ばれた画像の URL |
| 5 | Console で $0.getBoundingClientRect().width |
実際の表示幅(sizes と比べる) |
キャッシュを無効にするのが大切です。 一度大きな画像を読み込むと、画面幅を小さくしてもキャッシュ済みの大きな画像を使い続けることがあり、正しく確認できません。画面幅ごとにページを再読み込みして確かめます。
picture でアートディレクションと AVIF/WebP 切り替え
picture 要素は、条件ごとに別の画像を出し分けるための要素です。 中に source を並べ、最後に img を置きます。上から順に条件を確かめ、最初に合った source が使われます。
スマホとPCで切り抜きを変える(アートディレクション)
<picture>
<!-- 767px 以下:正方形に切り抜いた画像 -->
<source media="(max-width: 767px)"
srcset="images/hero-sq-640.jpg 640w, images/hero-sq-1280.jpg 1280w"
sizes="100vw" width="1280" height="1280">
<!-- それ以外:横長の画像 -->
<img src="images/hero-wide-2560.jpg"
srcset="images/hero-wide-1280.jpg 1280w, images/hero-wide-2560.jpg 2560w"
sizes="100vw" width="2560" height="1440" alt="メインビジュアル">
</picture>
実行結果:
D 375 DPR2 → hero-sq-1280.jpg DL:[hero-sq-1280.jpg]
D 767 DPR1 → hero-sq-1280.jpg DL:[hero-sq-1280.jpg]
D 768 DPR1 → hero-wide-1280.jpg DL:[hero-wide-1280.jpg]
D 1440 DPR1 → hero-wide-2560.jpg DL:[hero-wide-2560.jpg]
D 1440 DPR2 → hero-wide-2560.jpg DL:[hero-wide-2560.jpg]
767px までは正方形、768px からは横長の画像に切り替わりました。 source に width・height を書くと、画像ごとに縦横比が違っても、読み込み前に正しい高さが確保されます。
AVIF → WebP → JPEG の順に出し分ける
<picture>
<source type="image/avif" srcset="images/item-800.avif 800w, images/item-1600.avif 1600w"
sizes="(min-width: 1024px) 800px, 100vw">
<source type="image/webp" srcset="images/item-800.webp 800w, images/item-1600.webp 1600w"
sizes="(min-width: 1024px) 800px, 100vw">
<img src="images/item-800.jpg" srcset="images/item-800.jpg 800w, images/item-1600.jpg 1600w"
sizes="(min-width: 1024px) 800px, 100vw" width="1600" height="900" alt="商品写真">
</picture>
E 1440 DPR1 表示幅800px → item-800.avif DL:[item-800.avif]
E 375 DPR3 表示幅375px → item-1600.avif DL:[item-1600.avif]
Chromium 141 は最初の AVIF を選び、WebP と JPEG はダウンロードしませんでした。 形式の切り替えとサイズの切り替えは同時に使えます。各 source に srcset と sizes を書くのを忘れないようにします。
| picture の使い方 | source の属性 | 判断のしかた |
|---|---|---|
| アートディレクション | media |
条件に合った最初の source |
| 形式の出し分け | type |
ブラウザが対応している最初の形式 |
| 両方 | media と type |
両方の条件に合った最初の source |
alt・width・height・loading・fetchpriority は img 側に書きます。 source に書いた画像も、表示とスタイルは img 要素として扱われます。画像を枠いっぱいに切り抜いて表示する方法は「CSS object-fit・aspect-ratio」の記事で扱っています。
sizes="auto" と loading="lazy" の関係
sizes="auto" は、遅延読み込みの画像に限り、ブラウザが実際のレイアウト幅を表示幅として使う指定です。 遅延読み込みの画像はレイアウトが決まってから読み込まれるため、sizes を手で計算しなくて済みます。
<div class="card" style="width: 300px">
<img loading="lazy"
src="images/photo-800.jpg"
srcset="images/photo-320.jpg 320w, images/photo-640.jpg 640w, images/photo-1280.jpg 1280w"
sizes="auto, 100vw"
width="1600" height="900" alt="">
</div>
auto の後ろに通常の sizes を続けて書くと、未対応ブラウザではそちらが使われます。 ページの下のほう(6000px 下)に幅 300px のカードを置き、loading="lazy" 付きと、lazy なしの2枚で比べました。
F 1440 DPR1 スクロール前DL:[card-1200.jpg]
F lazy+auto 1440 DPR1 表示幅300px → photo-320.jpg DL:[card-1200.jpg,photo-320.jpg]
F eager+auto 1440 DPR1 表示幅300px → card-1200.jpg
F 1440 DPR2 スクロール前DL:[card-1200.jpg]
F lazy+auto 1440 DPR2 表示幅300px → photo-640.jpg DL:[card-1200.jpg,photo-640.jpg]
| 画像 | 読み込み時期 | 選ばれた画像 | 理由 |
|---|---|---|---|
lazy + sizes="auto, 100vw"(DPR 1) |
スクロールしてから | photo-320 | 実際の幅 300px を使った |
lazy + sizes="auto, 100vw"(DPR 2) |
スクロールしてから | photo-640 | 300px × 2 |
lazy なし + sizes="auto, 100vw" |
ページを開いてすぐ | card-1200(候補の最大) | auto が使われず、100vw(1440px)で選ばれた |
lazy のない画像では auto が使われず、後ろの 100vw で大きな画像が選ばれました。 sizes="auto" は loading="lazy" とセットで使います。
| ブラウザ | sizes="auto" 対応(MDN 互換性データ 8.1.4) |
|---|---|
| Chrome / Edge | 126 以降 |
| Firefox | 150 以降 |
| Safari / iOS Safari | 27 以降 |
LCP 画像の書き方(fetchpriority・lazy・width/height)
LCP(Largest Contentful Paint)とは、ページを開いて最も大きな要素が表示されるまでの時間で、Core Web Vitals の指標の1つです。 ファーストビューのメイン画像が LCP 要素になることが多いため、次のように書きます。
<!-- ファーストビューのメイン画像 -->
<img src="images/hero-1600.jpg"
srcset="images/hero-800.jpg 800w, images/hero-1600.jpg 1600w, images/hero-2400.jpg 2400w"
sizes="100vw"
width="1600" height="900"
fetchpriority="high"
alt="新しいタスク管理画面のイメージ">
| 属性 | LCP 画像 | ファーストビュー外の画像 |
|---|---|---|
fetchpriority |
high |
書かない(既定) |
loading |
書かない(lazy にしない) | lazy |
width / height |
必ず書く | 必ず書く |
sizes |
手で正確に書く(auto は使えない) | auto, ... が使える |
decoding |
書かなくてよい | 書かなくてよい |
Chromium 141 で、3枚の画像のリクエスト時の優先度(CDP の Network.requestWillBeSent の initialPriority)を記録しました。
{"photo-1600.jpg":"High","photo-1024.jpg":"Medium","photo-1280.jpg":"Low"}
| 画像 | 指定 | 最初の優先度 |
|---|---|---|
| photo-1600 | fetchpriority="high" |
High |
| photo-1024 | 指定なし | Medium |
| photo-1280 | loading="lazy"(ファーストビュー内) |
Low |
fetchpriority="high" の画像は最初から High で要求され、lazy の画像は Low で要求されました。 ファーストビューの画像を lazy にすると、表示が後回しになりやすくなります。なお、ブラウザはレイアウト後に優先度を変えることがあり、ここで示したのは最初の値です。
width と height を書くと、画像を読み込む前に縦横比から高さが確保され、レイアウトのずれ(CLS)を防げます。 CSS で max-width: 100%; height: auto; を指定しておけば、表示は親の幅に合わせて縮みます。
WordPress の自動 srcset を確認する方法
WordPress は、メディアライブラリの画像を本文やテーマで出力するとき、生成済みのサイズ違いの画像から srcset と sizes を自動で付けます。 以下は WordPress 公式の開発者向け情報に基づく内容で、本記事では WordPress を動かしての確認はしていません。
| 機能 | 内容 | 関連するフィルター・関数 |
|---|---|---|
| srcset の自動付与 | 同じ縦横比のサイズ違い画像を srcset に並べる | wp_calculate_image_srcset |
| srcset に入れる最大幅 | 既定は 2048px | max_srcset_image_width |
| sizes の既定値 | (max-width: {幅}px) 100vw, {幅}px |
wp_calculate_image_sizes |
| sizes="auto"(6.7 以降) | lazy の画像だけ、sizes の先頭に auto, を付ける |
wp_img_tag_add_auto_sizes(false で無効化) |
| fetchpriority(6.3 以降) | LCP になりそうな画像に fetchpriority="high" を付ける |
wp_get_loading_optimization_attributes |
確認の手順です。
- 公開ページを開き、DevTools の Elements タブで img を選んで srcset と sizes が付いているか見る
sizes="auto, (max-width: ...) 100vw, ...px"になっていれば、6.7 以降の自動 sizes が有効- 上の「DevTools で確かめる方法」の手順で、実際にダウンロードされた画像の幅を確認する
- 表示幅に対して大きすぎる画像が選ばれる場合は、テーマ側で
wp_calculate_image_sizesフィルターを使い、レイアウトに合った sizes を返す
// functions.php:本文の画像の sizes をコンテンツ幅(最大 760px)に合わせる例
add_filter('wp_calculate_image_sizes', function ($sizes, $size) {
$width = $size[0];
if ($width >= 760) {
return '(min-width: 800px) 760px, calc(100vw - 32px)';
}
return $sizes;
}, 10, 2);
この PHP コードは公式ドキュメントのフィルターの引数($sizes と $size)に沿った例で、実行はしていません。テーマのコンテンツ幅に合わせて値を変えてください。
srcset・sizes のチェックリスト
| チェック項目 | 確認 |
|---|---|
| 表示幅が固定なら x、変わるなら w + sizes を使った | |
| sizes は CSS の表示幅と一致している | |
| sizes の最後に条件なしの既定値を書いた | |
| 候補の最大幅は「最大の表示幅 × 想定 DPR」を目安にした | |
| width・height 属性を書いた | |
| LCP 画像は fetchpriority="high"、lazy にしていない | |
| ファーストビュー外は loading="lazy"(+ sizes="auto, ...") | |
| picture の source は AVIF → WebP の順、img に JPEG | |
| DevTools でキャッシュ無効にして実際の画像を確かめた |
よくある質問
Q. srcset だけで sizes を書かないとどうなりますか?
A. w 記述子の場合、sizes は 100vw とみなされます。 画面幅いっぱいの画像なら問題ありませんが、カードやサイドバーの画像では大きすぎる画像が読み込まれます(本記事の計測では表示 309px に対して 1600px の画像)。
Q. 画面を小さくしても画像が切り替わりません。 A. すでに大きな画像を読み込んでいると、ブラウザはそれを使い続けることがあります。 DevTools で「Disable cache」にして、画面幅ごとに再読み込みして確認します。
Q. picture と img の srcset はどう使い分けますか? A. 同じ画像のサイズ違いなら img の srcset、切り抜きや形式を変えるなら picture です。picture の中でも source と img のそれぞれに srcset と sizes を書けます。
Q. すべての画像に sizes="auto" を使えますか?
A. auto が使われるのは loading="lazy" の画像だけです。 ファーストビューの画像は lazy にしないため、sizes を手で書きます。
まとめ
- srcset は w 記述子(幅)と x 記述子(密度)があり、表示幅が変わる画像は w + sizes で書きます。
- ブラウザは「sizes の表示幅 × DPR」以上の最小の画像を選び、Chromium 141 の計測でも規則どおりでした。
- sizes を書かないと 100vw とみなされ、3列カードでは表示の5倍の幅の画像が読み込まれました。
- picture は media で切り抜きを、type で AVIF/WebP/JPEG を出し分けます。
- sizes="auto" は loading="lazy" とセットで使い、lazy なしでは後ろの値が使われます。
- LCP 画像は fetchpriority="high"、lazy にしない、width/height を書く、の3点を押さえます。
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「srcset・sizesの使い方|picture併用とDevToolsでの検証」
株式会社RJCでは、表示速度と画質を両立する画像の扱い方を仲間と学び合っています。こうした知識を共有しながら、日々技術を磨いています。
株式会社RJC ― SI事業・SES事業・AI駆動開発。RJCは一緒に成長を楽しめる会社です。
WE ARE HIRING
RJCで一緒に開発しながら、
成長を楽しみませんか?
RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!
- 127日年間休日
- 12時間平均残業時間
- 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!
ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。