image-set()で背景画像を出し分ける Retina対応や次世代フォーマットの対応方法

はじめに

背景画像を使う場合、見た目をきれいに保ちたい一方で、画像の重さはできるだけ抑えたい場面がよくあります。これまではメディアクエリやJavaScriptで細かく分岐することもありましたが、画像の解像度やフォーマットの違いをもっと素直に書きたいケースも多いです。

そんなときに便利なのが CSS の image-set() です。
image-set() は、複数の画像候補を CSS 側でまとめて指定し、その中からブラウザに最適なものを選んでもらうための関数です。主な用途は高ピクセル密度ディスプレイ向けの画像切り替えですが、MDN ではフォーマットごとの出し分けにも使えることが案内されています。

たとえば、同じ背景画像でも 1x と 2x の解像度違いを並べておけば、高解像度ディスプレイではより細かい画像が選ばれます。さらに type() を組み合わせると、AVIF を優先しつつ、未対応環境では JPEG を使うといった構成も CSS だけで書けます。

押さえておきたいポイントは次の3つです。

  • 画像候補ごとに解像度や MIME type を付けられる
  • ブラウザが端末や環境に応じて適切な候補を選ぶ
  • 主戦場は background-image などの CSS 画像で、内容理解に必須の画像には向かない

基本の使い方

最初は、背景画像を 1x と 2x で切り替える最小例です。ヒーローやカード一覧のサムネイル背景など、まずは「Retina 対応したいが HTML は増やしたくない」場面で使うと分かりやすいです。

HTML

HTML
<section class="hero-banner">
  <div class="hero-banner__content">
    <h2>Spring Campaign</h2>
    <p>背景画像を端末に合わせて切り替えます。</p>
  </div>
</section>

CSS

CSS
.hero-banner {
  min-height: 360px;
  padding: 32px;
  color: #fff;
  background-color: #0f172a;
  background-repeat: no-repeat;
  background-position: center;
  background-size: cover;
  background-image: image-set(
    url("/images/hero-banner@1x.jpg") 1x,
    url("/images/hero-banner@2x.jpg") 2x
  );
}

この形なら、CSS の責務を崩さずに高解像度対応を足せます。background-size: cover と組み合わせると、ヒーローのような大きな背景でも扱いやすいです。

image-set() の解像度指定には x だけでなく dppxdpidpcm も使えますが、実務では 1x2x がもっとも読みやすいと思います。なお、同じ image-set() の中では解像度を重複させないのが前提です。

image-set() が特に便利なのは、HTML 側を増やしたくない背景画像の最適化です。たとえば次のような場面で使いやすいです。

  • ヒーロー背景を 1x / 2x で出し分ける
  • カード一覧の背景サムネイルを高密度画面だけ高精細にする
  • AVIF を優先しつつ、未対応ブラウザには JPEG を渡す
  • LP の装飾背景で軽さと見た目のバランスを取りたい

逆に、記事本文の図版や商品画像のように内容理解そのものに関わる画像には、<img><picture> を優先したほうが安全です。背景画像は支援技術に意味が伝わらないため、MDN でも重要な情報を背景画像だけに載せないことが案内されています。

応用コード

次は、解像度だけでなく画像フォーマットも含めて出し分ける例です。実務では「AVIF が使えれば軽くしたいが、古い環境も落としたくない」というケースが多いので、このパターンがかなり実用的です。

HTML

HTML
<article class="feature-card">
  <div class="feature-card__media"></div>
  <div class="feature-card__body">
    <h3>導入事例</h3>
    <p>背景画像の最適化を CSS 側でまとめて管理します。</p>
  </div>
</article>

CSS

CSS
.feature-card {
  display: grid;
  gap: 16px;
  max-width: 640px;
}

.feature-card__media {
  min-height: 240px;
  border-radius: 20px;
  background-repeat: no-repeat;
  background-position: center;
  background-size: cover;
  background-image: image-set(
    url("/images/case-study.avif") type("image/avif") 1x,
    url("/images/case-study@2x.avif") type("image/avif") 2x,
    url("/images/case-study.jpg") type("image/jpeg") 1x,
    url("/images/case-study@2x.jpg") type("image/jpeg") 2x
  );
}

この構成にしておくと、画像フォーマットの選択と高解像度対応をひとつの宣言にまとめられます。HTML 側に <picture> を追加せずに済むので、装飾用途の背景画像ならかなり扱いやすいです。

もうひとつ practical にするなら、カスタムプロパティと組み合わせてコンポーネント化する方法もあります。

CSS

CSS
.promo-panel {
  --promo-image-1x: url("/images/promo-default.jpg");
  --promo-image-2x: url("/images/promo-default@2x.jpg");
  --promo-color: #111827;

  min-height: 320px;
  border-radius: 24px;
  background-color: var(--promo-color);
  background-position: center;
  background-size: cover;
  background-image: image-set(
    var(--promo-image-1x) 1x,
    var(--promo-image-2x) 2x
  );
}

.promo-panel[data-theme="summer"] {
  --promo-image-1x: url("/images/promo-summer.jpg");
  --promo-image-2x: url("/images/promo-summer@2x.jpg");
  --promo-color: #0c4a6e;
}

デザイン違いのバリエーションが多い案件では、この形にしておくと管理しやすくなります。画像差し替えのたびに background-image を丸ごと書き直さなくて済むので、運用も軽くなります。

注意点

image-set() は便利ですが、いくつか先に知っておきたい点があります。

まず、背景画像はアクセシビリティ上の意味を持たせにくいです。スクリーンリーダーは背景画像の内容を伝えないため、情報として必須の画像を background-image に置くのは避けたほうが安全です。

次に、image-set() は「どれを使うかをブラウザに委ねる」仕組みです。解像度や帯域の状況をもとに選ばれるため、常に作者の想定どおりのファイルが選ばれるとは限りません。この性質を理解したうえで、「選択ルールを自分で固定したい」のか、「候補だけ渡してブラウザに最適化してほしい」のかを切り分ける必要があります。

そのほか、実装時は次も確認しておくと安全です。

  • 同じ image-set() の中で解像度を重複させない
  • 装飾目的なら background-image、内容画像なら <img> / <picture> を優先する
  • フォーマット出し分けでは type() を併用すると意図が明確になる
  • 開発者ツールで実際にどの画像が取得されているか確認する

まとめ

image-set() を使うと、背景画像の高解像度対応や次世代フォーマット対応を CSS 側でかなり素直に書けます。HTML を増やさずに最適化したいときには、かなりちょうどいい選択肢です。

特に、ヒーロー背景、装飾カード、LP のビジュアルのような「見た目には効かせたいが、意味づけは不要」という画像に向いています。まずは 1x / 2x の切り替えから始めて、必要に応じて type() を足すと導入しやすいです。

ポイント

  • image-set() は CSS で画像候補をまとめ、ブラウザに最適なものを選ばせる仕組み
  • 高解像度対応だけでなく、type() を使ったフォーマット出し分けにも向いている
  • 主な用途は background-image などの装飾画像で、内容理解に必須の画像には向かない
  • MDN では 2023年9月から主要ブラウザで広く使える機能として案内されている
  • まずは 1x2x の切り替えから始めると導入しやすい

参考リンク

read next