背景画像のレスポンシブ設計:CSS image-set() / aspect-ratio / object-fit の最短実装
背景画像は CSSの都合で srcset/sizes
が使えないため、実装を誤ると 「解像度不足」「容量過大」「表示時に押し下げ(CLS)」のどれかでつまずきます。結論はimage-set() + aspect-ratio + breakpoint切替の三点セット。意味のある画像は<img>へ寄せるのが近道です。
先に結論(型を決めて自動化)
- 役割で分岐:内容を伝える画像は
<img>
、純装飾は CSS 背景。 - 予約サイズ:
aspect-ratio
かmin-height
を先出し( CLSゼロ設計 参照)。 - image-set():AVIF/WebP/JPEG を 1x/2x で宣言。解像度差は breakpoint で差し替え。
要点(TL;DR)
- 背景は image-set() でコーデック切替(AVIF/WebP/JPEG)+1x/2x。
- 画面幅でのサイズ最適化はメディアクエリで差し替え(CSSは dppx 判定のみのため)。
aspect-ratio
で予約サイズを先出し。背景色を塗って初期フレームを安定化。- 意味のある画像は
<img>
(srcset/sizes
が使えて LCP も最適化しやすい)。関連: srcset/sizes設計。
1. なぜ image-set()
なのか
CSS 背景は srcset/sizes
が無く、ブラウザは画面のピクセル密度(dppx)だけを見て候補を選びます。 そのため幅に応じた候補は メディアクエリで差し替える必要があります。 また、CLS防止のために予約サイズを先に確保するのが定石です。
2. 最短フロー(実務)
- まず意味の有無で分岐(装飾なら背景、内容なら
<img>
)。アクセシビリティ/SEOの基礎です。 - 背景は aspect-ratio(または
min-height
)で予約サイズを確保し、image-set()
に AVIF/WebP/JPEG を順に並べます。 - 画面幅に応じて
@media (min-width: …)
で候補群を差し替えます(CSS は dppx 想定のため)。 - LCP 候補の背景は、代表的に採用されやすい 1枚を
<link rel="preload" as="image">
で先読み(やりすぎ注意)。
3. 実装レシピ(コピペOK)
3.1 マークアップ(装飾としての背景)
// HTML<!-- 意味のない装飾なら CSS 背景。アクセシビリティ上は aria-hidden を付与 -->
<div class="hero" aria-hidden="true">
<div class="hero__inner">
<h1>見出し</h1>
<p>キャッチコピー</p>
</div>
</div>
3.2 CSS:image-set() + aspect-ratio
// CSS/* 背景ヒーロー:aspect-ratio で予約サイズ。背景は cover / center でトリミング */
.hero {
aspect-ratio: 16 / 9;
min-height: 42vh; /* 端末縦が極端に小さい場合の保険 */
background-color: #e5e7eb; /* 先に塗っておくと初期フレームが安定 */
background-repeat: no-repeat;
background-position: center;
background-size: cover;
/* まずは JPEG をフォールバックとして指定(旧ブラウザ保険) */
background-image: url("/images/hero-800.jpg");
/* 次に image-set() で AVIF/WebP の候補を載せる(1x/2x) */
background-image: image-set(
url("/images/hero-800.avif") type("image/avif") 1x,
url("/images/hero-1600.avif") type("image/avif") 2x,
url("/images/hero-800.webp") type("image/webp") 1x,
url("/images/hero-1600.webp") type("image/webp") 2x,
url("/images/hero-800.jpg") type("image/jpeg") 1x,
url("/images/hero-1600.jpg") type("image/jpeg") 2x
);
}
/* デスクトップではもう一段解像度を上げる(CSSは“dppxベース”なので breakpoint で差し替える) */
@media (min-width: 1024px) {
.hero {
background-image: url("/images/hero-1200.jpg");
background-image: image-set(
url("/images/hero-1200.avif") type("image/avif") 1x,
url("/images/hero-2400.avif") type("image/avif") 2x,
url("/images/hero-1200.webp") type("image/webp") 1x,
url("/images/hero-2400.webp") type("image/webp") 2x,
url("/images/hero-1200.jpg") type("image/jpeg") 1x,
url("/images/hero-2400.jpg") type("image/jpeg") 2x
);
}
}
.hero__inner {
max-width: 72rem;
margin: 0 auto;
padding: 4rem 1rem;
color: #111827;
text-shadow: 0 1px 0 rgba(255,255,255,.6);
}
3.3 LCP候補ならプリロード
// HTML<!-- LCP候補の背景画像(代表的に採用されやすい1枚)を先読み -->
<link rel="preload" as="image" href="/images/hero-1200.avif" type="image/avif">
3.4 意味のある画像は <img> + object-fit
// HTML + CSS<!-- 意味のある画像(alt が必要)なら <img> で表現し、object-fit でカバー -->
<figure class="hero-img">
<img
src="/images/hero-1200.avif"
srcset="/images/hero-800.avif 800w, /images/hero-1200.avif 1200w, /images/hero-1600.avif 1600w"
sizes="(min-width: 1024px) 1000px, 92vw"
width="1600" height="900"
alt="製品の利用シーン"
fetchpriority="high"
decoding="async"
/>
<figcaption class="sr-only">製品の利用シーンの写真</figcaption>
</figure>
<style>
.hero-img { aspect-ratio: 16 / 9; }
.hero-img > img { width: 100%; height: 100%; object-fit: cover; }
</style>
3.5 Next.js 15 での推奨(意味のあるヒーロー)
// TSX (Next.js)// Next.js 15:意味のあるヒーロー画像は next/image を推奨
// 注意: 背景装飾には <div style=background-image> が適任です
/*
import Image from "next/image";
export default function Hero() {
return (
<div className="relative" style={{ aspectRatio: "16/9" }}>
<Image
src="/images/hero-1600.avif"
alt="製品の利用シーン"
fill
sizes="(min-width: 1024px) 1000px, 92vw"
priority
/>
</div>
);
}
*/
4. 応用と使いどころ
- テキストを重ねるカードでは、背景画像に
linear-gradient()
を足して可読性を担保。色はまず sRGB正規化 を。 - 画像の画質・容量は /compressor でサイズを、劣化は /compare で確認。
- 背景では
decoding
/loading
の制御ができないため、重要画像はできるだけ<img>
側へ寄せるほうが CWV 的に安定。
5. 公開前チェック
// Checklist# 公開前チェック(背景画像)
- 役割の切り分け:意味のある画像は <img> / 装飾は CSS 背景
- 予約サイズ:aspect-ratio または min-height で CLS を防止
- image-set():1x/2x & AVIF/WebP/JPEG の順に宣言(先に JPEG を url() で保険)
- breakpoint:モバイルとデスクトップで背景の候補群を切り替え
- LCP:ヒーローが背景なら代表サイズを <link rel="preload"> で先読み
- 画質と容量:/compare で劣化を確認、/compressor でサイズ目安を満たす
6. まとめ
背景は image-set() + aspect-ratio + breakpoint差し替えの型を決めてしまえば運用が楽です。 重要画像は <img>
で最短に配信、装飾は CSS 背景で“崩れない見え”に。最後は /compare と /compressor で仕上げを確認しましょう。
FAQ(よくある質問)
画像形式の基本方針は?(写真/スクショ/透過)
写真は AVIF / WebP(画質80–85%目安)、UIやスクショはPNG / WebP Lossless、単色ロゴはSVGが基本です。 実装の詳細は srcset/sizes設計ガイド と スクショ最適化 を参照してください。
圧縮しても画質を落とさないコツは?
実表示幅に合わせたリサイズ → 過大ダウンロードを防ぎ、
srcset/sizes
を 実描画幅に一致させます。画質は写真で 80–85% を起点に、ノイズやエッジを目視確認。 仕上げは /compare で Before/After を見比べるのがおすすめです。