pictureを使って、ビューポートのブレークポイントで正方形と横長の画像ファイルを切り替えます。各ソースにそれぞれの寸法を指定し、選択された画像をCSSで比例を保って拡大縮小します。このガイドでは、Mac上でローカルのサンプルを作成してテストします。

pictureは異なるアスペクト比をどのように切り替えるのですか?

フォールバックのimgより前に、picture内へmedia条件を指定したsource要素を置きます。ブラウザーは、条件に一致する最初の適格なソースを選び、そのソースのsrcsetから画像を選択します。これはアートディレクションと呼ばれ、レイアウトに応じて異なる構図を提供する手法です。HTML Standardはこの方法を明示的にサポートしています。HTML Standard: Images

3つの要素が連携します。ソースがリソースを選び、寸法属性がそのリソースの比率を示し、CSSが表示サイズを制御します。選択されたソースのwidthとheightは、内包された画像に使われるアスペクト比を提供できます。picture要素自体は画像を描画せず、そのimgが描画します。HTML Standard: Embedded content

必要な結果に応じて仕組みを選びます。

要件 適切な仕組み
ブレークポイントで構図またはアスペクト比を変更する pictureと、mediaを使うsource
同じ構図の異なる解像度を提供する srcset。幅記述子を使う場合はsizes
1つのファイルを固定フレーム内で切り抜く CSSのサイズ指定とobject-fit: cover

これらの仕組みは、それぞれ異なる判断に対応します。アートディレクションは、どの構図を表示するかを決めます。解像度の選択では、ブラウザーが1つの構図の中から適切な候補を選びます。CSSのフィッティングは、選択されたリソースをフレーム内にどのように収めるかを決めます。MDNでは、pictureのこうした用途と、srcsetやフィッティングプロパティとの関係が説明されています。MDN: The picture element

Macでローカルのサンプルを作成する

このサンプルでは、オレンジ色の円とティール色の角丸長方形を含む、2つのSVGリソースを自作します。正方形版では図形を上下に並べ、横長版では横に並べます。切り替えに外部アセットやJavaScriptは不要で、すべて1つのフォルダーに保存します。

作成するリソースの仕様はシンプルです。ビューポート幅が700px未満の場合は、600 × 600の正方形リソースを使います。700px以上では、1200 × 600の横長リソースを使います。表示画像は、左右に16pxの余白を設けたコンテンツ領域いっぱいに広がり、最大幅は960pxです。これらの寸法とブレークポイントは、説明用に選んだ値です。

2つの図形リソースを保存する

picture-demoという名前のフォルダーを作成します。プレーンテキストに対応したコードエディターで、次の2つのファイルをその中に作成し、ファイル名と拡張子を正確に保ちます。それぞれのコードブロックにはファイルの内容全体が含まれています。Markdownのフェンス記号を除いてコピーしてください。

shapes-square.svgとして保存します。

<svg xmlns="http://www.w3.org/2000/svg" width="600" height="600" viewBox="0 0 600 600">
  <rect width="600" height="600" fill="#fff5df"/>
  <circle cx="300" cy="180" r="100" fill="#de7b35"/>
  <rect x="150" y="340" width="300" height="160" rx="40" fill="#247d83"/>
</svg>

shapes-wide.svgとして保存します。

<svg xmlns="http://www.w3.org/2000/svg" width="1200" height="600" viewBox="0 0 1200 600">
  <rect width="1200" height="600" fill="#fff5df"/>
  <circle cx="320" cy="300" r="180" fill="#de7b35"/>
  <rect x="650" y="150" width="400" height="300" rx="60" fill="#247d83"/>
</svg>

HTMLページを保存する

同じフォルダーにindex.htmlを作成します。TextEditを使う場合は、コードを貼り付ける前にFile > Newを選び、続けてFormat > Make Plain Textを選択します。ファイルを.html拡張子で保存し、確認が表示されたらUse .htmlを選びます。Appleは、HTMLファイルを作成するこの手順を説明しています。Apple: Work with HTML documents in TextEdit on Mac

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Shape study</title>
  <style>
    body { margin: 0; font-family: system-ui, sans-serif; }
    main { width: calc(100% - 32px); max-width: 960px; margin: 24px auto; }
    picture { display: block; }
    .study-image { display: block; width: 100%; height: auto; }
  </style>
</head>
<body>
  <main>
    <h1>Shape study</h1>
    <picture>
      <source media="(min-width: 700px)" srcset="shapes-wide.svg"
              width="1200" height="600">
      <img class="study-image" src="shapes-square.svg"
           width="600" height="600"
           alt="An orange circle and a teal rounded rectangle on cream.">
    </picture>
    <p>Resize the viewport to compare the two arrangements.</p>
  </main>
</body>
</html>

Safariでindex.htmlを開きます。ビューポートが十分に広ければ、図形は横に並んで表示されます。ビューポートが狭ければ、上下に並びます。3つのファイルはすべて同じ場所に置いてください。相対リソースURLは、HTMLファイルの場所を基準に解決されます。

横長ソースでは、URLが1つしか含まれていなくてもsrcsetを使っています。picture内では、sourceにsrcsetが必要で、そのsrc属性は使用できません。寸法属性は単位のない整数なので、width="1200"を使い、width="1200px"は使いません。MDN: The source element

sourceとフォールバックの両方に寸法を指定する理由

フォールバックの600 × 600という寸法は、正方形リソースの寸法を示します。横長ソースの1200 × 600という寸法は、横長リソースの寸法を示します。両方の寸法を指定すると、対応ブラウザーはダウンロード前に、選択した画像の比率を確定できます。横長ソースに正方形の寸法を再利用すると、初期比率が誤って伝わります。HTML Standard: Source dimension attributes

そのうえでCSSは、幅を利用可能なコンテンツ幅に設定し、高さは自動のままにします。高さを自動にすることで、画像の比率に応じて高さが決まります。CSS sizing draftでは、推奨アスペクト比が自動サイズ指定にどのように関与するかが説明されています。両方の寸法を明示的に固定すると、この柔軟性は失われます。CSS Box Sizing Module Level 4

このサンプルのレイアウトは、次の簡単な計算で確認できます。

画像の幅 = min(ビューポートの幅 - 32, 960)
正方形の高さ = 画像の幅
横長の高さ = 画像の幅 / 2
CSSピクセルでのビューポート幅 選択されるリソース 計算上の画像サイズ
500 shapes-square.svg 468 × 468
699 shapes-square.svg 667 × 667
700 shapes-wide.svg 668 × 334
1000 shapes-wide.svg 960 × 480

これらは、スクロールバーの幅によって利用可能なコンテンツ領域が狭まらないと仮定した場合の、指定CSSに基づく計算上の予測値です。SVG構文、リソース名、宣言された寸法、計算はプログラムで確認しました。準備中にサンプルをブラウザーで表示してはいません。

699pxから700pxの間で高さが大きく変わることに注目してください。正方形の構図から横長の構図に切り替わるために起きる変化です。サイズ変更時には想定される動作です。ビューポートを固定したまま読み込み後にもう一度跳ねる場合は、宣言された寸法と上書きされたCSSを確認してください。

Safariでブレークポイントを正確にテストする

Safariのレスポンシブデザインモードでは、デスクトップのウィンドウとは別にページのビューポートをサイズ変更できます。SafariのAdvanced設定で、Show features for web developersを有効にします。サンプルを開き、Develop > Enter Responsive Design Modeを選ぶか、Control-Command-Rを押します。WebKitでは、設定、ショートカット、サイズ変更可能なプレビューについて説明しています。WebKit: Simplified Responsive Design Mode

まず699pxと700pxをテストし、その後、十分に狭い幅と広い幅を試します。意図した境界で構図が切り替わること、オレンジ色の図形が円形を保つこと、画像の下の段落が画像の高さの変化に合わせて配置されることを確認します。ブレークポイントの両側で再読み込みし、サイズ変更時だけでなく初期レイアウトも確認します。

Safariがどのファイルを選んだか直接確認するには、サンプルを表示中にWeb Inspectorのコンソールで次の診断用スニペットを実行します。この手順は任意です。

const studyImage = document.querySelector('.study-image');
if (!studyImage) {
  throw new Error('Open the Shape study example before running this snippet.');
}
const studyBox = studyImage.getBoundingClientRect();
console.table({
  selectedURL: studyImage.currentSrc,
  displayedWidth: studyBox.width,
  displayedHeight: studyBox.height
});

ブレークポイントをまたいだ後、もう一度スニペットを実行します。選択されたURLの末尾は、該当する正方形または横長のファイル名になるはずです。currentSrcプロパティは、ブラウザーが選んだURLを示します。この値だけでは、リソースの読み込みが成功したとは確認できません。MDN: HTMLImageElement currentSrc property

切り替えがうまくいかないときに確認すること

まず選択、次にリソースの寸法、最後に表示方法の順で確認します。こうすれば、CSSのサイズ指定に関する問題を、リソース選択の問題と取り違えずに済みます。

  1. 幅が広くても正方形のファイルが選択される。 ビューポートが700pxに達していること、sourceがimgより前にあること、ソースでsrcsetを使っていることを確認します。複数のソースがある場合は順序も調べてください。先にある一致ソースが優先される場合があります。HTML Standard: Art direction selection
  2. リソースが表示されない。 マークアップ内のファイル名とフォルダー内のファイルを、拡張子も含めて照合します。このサンプルでは、2つのSVGファイルをindex.htmlと同じ場所に置く必要があります。
  3. 適切なリソースが誤った形で表示される。 実際のimgに適用されているCSS、特に高さを固定するルールを確認します。比率を保ってサイズを変えるには、height: autoに戻します。
  4. 読み込み後に画像が跳ねる。 宣言された各寸法とリソースの実際の比率を照合します。また、明示的なCSSのaspect-ratioが意図した比率を上書きしていないか確認します。

実際のデザインで固定フレームが必要な場合は、フィッティングの動作を意図的に選びます。object-fit: containはリソース全体を保ち、余白が生じることがあります。coverはフレームを埋めますが、内容が切り取られる場合があります。fillは画像を引き伸ばすことがあります。フィッティングプロパティはimgに適用します。このサンプルでは、レイアウトが選択されたリソースの比率に従うため、固定フレームは必要ありません。MDN: object-fit

ブラウザーサポート上の制限は何ですか?

pictureのサポートと、ソース固有の寸法のサポートは別々に考える必要があります。HTML Standardの互換性概要では、現在のブラウザーエンジンでpictureがサポートされているとされています。MDNによると、寸法属性を反映するsourceのwidthプロパティは、2022年12月以降、各ブラウザーで利用可能です。古いブラウザーがソース固有の寸法を正しく確保すると想定してはいけません。HTML Standard: The picture element、MDN: HTMLSourceElement width property

一致するソースがない場合、またはブラウザーがpictureをサポートしていない場合は、フォールバックのimgが画像を提供します。このサンプルでは正方形の構図です。リソースは切り替えられてもソース寸法に対応していないブラウザーでは、横長画像の最終的な比率が読み込み後に確定することがあります。MDN: The picture element

対象ブラウザーがCSSのaspect-ratioをサポートしているものの、明示的なサイズ指定ルールが必要な場合は、次のCSS断片を既存のスタイルシートに追加します。HTMLのブレークポイントを反映し、暫定的な比率を指定しながら、読み込まれた画像の自然な比率を優先します。

.study-image {
  aspect-ratio: auto 1 / 1;
}

@media (min-width: 700px) {
  .study-image {
    aspect-ratio: auto 2 / 1;
  }
}

MDNでは、autoと比率を組み合わせる方法が説明されており、CSSのaspect-ratioは2021年9月以降、各ブラウザーで利用可能とされています。そのため、この断片にも独自のサポート範囲があります。ブレークポイントをソース条件と同期させ、実際に対応が必要なブラウザーのバージョンでテストしてください。MDN: aspect-ratio

サンプルが正しく動作したら、合成リソースを独自の構図に置き換え、寸法も合わせて更新します。ソース条件、リソースの比率、CSSのサイズ指定を一致させ、ブレークポイントのすぐ下と上で改めて確認してください。

出典