UIにおける画像・動画・音声などのメディアコンテンツを、レイアウトを崩さず・アクセシブルに・パフォーマンス良く表示するためのコンポーネント設計。アスペクト比固定・レイジーロード・スケルトンUI・エラー時フォールバックの4つが設計の核。
この記事を読むと、アスペクト比固定によるレイアウト崩れ防止・loading="lazy" の適切な適用・alt属性の正しい書き方・スケルトンUIとフォールバック画像の実装が自分でできるようになります。
1. UI例(Preview / Live)
実装で見る(GunjoUI)
この部品を、デザインシステム GUNJO の実装で確かめられます。
2. 定義(Definition)
UIに画像・動画・音声などのメディアコンテンツを表示するコンポーネント群の設計原則。単なる <img> タグの使い方ではなく、アスペクト比固定によるレイアウト安定性・レイジーロードによるパフォーマンス・フォールバックとスケルトンUIによるUX品質を一体で設計する考え方。
Avatarとの違い:Avatarは人物・エンティティを識別するための小さな円形UI。Image / Mediaはコンテンツそのもの(記事の画像・商品写真・動画)を表示する。
CardのMedia部分との違い:Cardコンポーネント内に含まれる画像領域もImage / Mediaの原則に従って設計する。Card自体はコンテナ、Image / Mediaは中のメディア表示ルール。
3. 使い分け(When to use / When NOT to use)
3.1 When to use
- 記事のサムネイル・OGP画像・アイキャッチなどのコンテンツ画像
- ECサイトの商品写真など製品の視覚情報が核となる場合
- 動画プレーヤー・音声プレーヤーなどのメディアプレーヤーUI
- ユーザーがアップロードした画像のプレビュー表示
- ダッシュボードのグラフ・チャート(静的画像として出力する場合)
3.2 When NOT to use
- ユーザーの識別子 →
Avatarを使う - アイコン・シンボル(機能の記号)→
Iconコンポーネントを使う - 背景の装飾画像 → CSS の
background-imageで実装し<img>は使わない
3.3 代替UI(Alternatives)
- 複数画像の切り替え →
Carousel - 画像の拡大表示 →
Modal+<img>の組み合わせ - 装飾的な背景 → CSS
background-image(alt不要の場合)
4. 設計判断の核(Decision Principles)
メディア表示の核は「レイアウトを崩さない」——アスペクト比を固定しないと、読み込み前後のレイアウトシフト(CLS)でユーザーが操作ミスを起こす。
判断の優先順位:① アスペクト比固定 → ② alt属性 → ③ レイジーロード → ④ フォールバック設計
- アスペクト比を必ず固定する:
aspect-video(16:9)やaspect-square(1:1)を使い、画像読み込み前から領域を確保する。これがないとCLS(Cumulative Layout Shift)が悪化しCore Web Vitalsに悪影響を与える loading="lazy"はファーストビュー外の画像のみ:ページ最上部のヒーロー画像にloading="lazy"を付けると初期表示が遅れる。スクロールで表示される画像のみに適用する- 装飾画像には
alt="":純粋に装飾目的の画像(背景パターン・絵柄など)はalt=""を設定してスクリーンリーダーにスキップさせる。コンテンツの意味を持つ画像には必ず説明的なテキストを書く object-coverでコンテナを埋める:サムネイル・カバー画像はobject-cover+object-position: centerでコンテナを均一に埋める。object-fillは縦横比を歪めるため基本的に使わない
5. 状態設計(States)
5.1 必須状態(Required)
- Loading(Skeleton):画像取得中のプレースホルダー表示(アスペクト比を維持したスケルトン)
- Loaded:画像が正常に表示されている状態
- Error:画像の読み込みに失敗した場合のフォールバック表示
5.2 条件付き状態(Conditional)
- Hover(インタラクティブな場合):クリック可能な画像でのズームイン・オーバーレイ表示
- Focus(クリッカブルな場合):キーボードフォーカス時のフォーカスリング
- Caption:キャプションテキストが添えられた状態(
<figure>+<figcaption>)
5.3 State Gallery
| 状態 | 必須 | 何を伝えるか |
|---|---|---|
| Loading(Skeleton) | ✅ | 読み込み中・領域を確保している |
| Loaded | ✅ | メディアコンテンツを正常に表示 |
| Error(Fallback) | ✅ | 画像を取得できなかった |
| Hover | — | クリック可能・インタラクティブ |
| Caption | — | メディアに付随する補足情報 |
6. バリエーション設計(Variants)
アスペクト比と
object-fitの組み合わせで用途を決める。
| バリアント | アスペクト比 | object-fit | 用途 |
|---|---|---|---|
| ヒーロー画像 | 16:9 / 21:9 | cover | 記事トップ・バナー |
| サムネイル | 16:9 / 4:3 | cover | カード・記事一覧 |
| 商品画像 | 1:1 | contain | EC商品・アイコン |
| ポートレート | 3:4 | cover | 人物・書影 |
| 動画プレーヤー | 16:9 | — | <video> 要素 |
禁止パターン:object-fill でコンテナに無理やり引き伸ばす → 縦横比が歪んで不自然な表示になる。object-cover(クリップ)または object-contain(余白あり)を使う。
7. パターン集(Good / Bad / How to fix)
7.0 よく崩れる設計パターン(3つ)
- アスペクト比未設定:画像読み込み前後にレイアウトが大きくシフトし、ユーザーがクリックしようとしたボタンが移動する(CLS問題)
- ファーストビュー画像に
loading="lazy":最初に表示される画像が遅延読み込みされ、初期表示が白いままになる - alt属性の省略または無意味な値:スクリーンリーダーがファイル名(
img-001.jpg)を読み上げるか、情報を完全にスキップする
7.1 Bad(典型3つ)
<img src={url} />のみでwidth・height・altなし。読み込み完了後にページが大きくジャンプする- ヒーロー画像に
loading="lazy"を設定。ファーストビューが空白のまま数秒表示される alt="image"やalt="写真"など意味のないalt。スクリーンリーダーに「写真」とだけ読み上げられる
7.2 Good(対になる3つ)
<div class="aspect-video"><img class="w-full h-full object-cover" /></div>でアスペクト比を維持したコンテナに画像を収める- ファーストビューには
loading="eager"(デフォルト)、スクロール先の画像のみにloading="lazy"を付与する alt="東京のスカイラインの写真。夕暮れ時にライトアップされた東京タワーが見える"のように内容を具体的に記述する
7.3 How to fix(手順)
- すべての
<img>をaspect-*クラスを持つコンテナで囲む - コンテナ内の
<img>にclass="w-full h-full object-cover"を設定する - ファーストビュー外の画像に
loading="lazy"を付与する - すべての
<img>に意味のあるaltを設定する(装飾画像はalt="") onErrorでフォールバック画像またはカスタムエラーUIに切り替える
8. ルール(Must / Better)
Must(守らないと壊れる)
Better(品質が跳ねる)
9. アクセシビリティ要件(必須)
Keyboard
- 装飾的な画像はフォーカス不要
- クリッカブルな画像(ギャラリー開く・リンク)は
<a>または<button>で囲みTabフォーカス可能にする
Focus
- クリッカブルな画像コンテナにフォーカスリングを表示する
<img>単体にはフォーカスを当てない(囲むインタラクティブ要素でフォーカスを管理)
Screen Reader
- コンテンツ画像:具体的で意味のある
altテキストを書く- 悪い例:
alt="写真"alt="image001" - 良い例:
alt="東京タワーの夜景。ライトアップされたタワーと周辺の街並み"
- 悪い例:
- 装飾画像:
alt=""を設定してスクリーンリーダーがスキップするようにする - 機能的な画像(ボタンのアイコンなど):
alt="検索"のように機能を表すテキストを書く
<!-- コンテンツ画像 -->
<figure>
<img
src="/tokyo-tower.jpg"
alt="東京タワーの夜景。ライトアップされたタワーと周辺の街並み"
loading="lazy"
class="w-full h-full object-cover"
/>
<figcaption>東京タワー(2024年撮影)</figcaption>
</figure>
<!-- 装飾画像 -->
<img src="/decorative-pattern.svg" alt="" aria-hidden="true" />
<!-- クリッカブルな画像 -->
<a href="/article/tokyo">
<img src="/thumbnail.jpg" alt="東京特集記事のサムネイル" />
</a>
Touch / Pointer
- クリッカブルな画像のタップ領域は最低44×44pxを確保する
- 小さいサムネイルに透明な
paddingを追加してタップ領域を拡張する
Contrast / Readability
- 画像の上にテキストオーバーレイを載せる場合は半透明の背景(
bg-black/50)を必ず使い、テキストのコントラスト比4.5:1以上を確保する - 画像だけでコンテンツの意味を伝えない(alt必須の理由)
10. 実装メモ(Implementation Notes)
- Next.js の
<Image>コンポーネントを使うと、自動的にsrcset生成・WebP変換・width/height属性の付与・レイジーロードが適用される。新規プロジェクトでは<img>より<Image>を優先する - スケルトンUIは
animate-pulseクラスのグレーのdivをアスペクト比固定コンテナで囲むだけで実装できる。画像の読み込み完了後 (onLoad) にスケルトンを非表示にする - フォールバック画像は
<img>のonErrorイベントでsrcを差し替えるか、ReactのuseStateでフォールバック表示に切り替える。ReactではonError={() => setImgSrc('/fallback.png')}が最もシンプル - CLS防止の最も確実な方法は、コンテナに固定の
width・heightまたはaspect-*クラスを指定してから<img>を入れること。<img>に直接width/height属性を書く方法もCLS防止に有効
11. 関連リンク
- 関連するUIデザイン原則: 視覚的階層 (Visual Hierarchy), スキャンしやすさ (Scannability), 情報密度 (Information Density)
- 用語集(定義): 視覚的階層 (Visual Hierarchy), 可読性 (Readability)
- 関連するUIコンポーネント(横): Card(カード), Avatar(アバター), Carousel(カルーセル)
12. まとめ
Image / Mediaの設計は「アスペクト比固定(CLS防止)」「意味のある alt 属性」「フォールバック実装」の3点が最低ラインです。迷ったら 4. 設計判断の核 に戻り、aspect-* によるコンテナ固定・loading="lazy" の適用範囲・object-cover と object-contain の使い分けを確認してください。画像はUIの中で最も容量が大きくパフォーマンスへの影響が高いコンポーネントです——コードの正しさだけでなく、Core Web Vitals(CLS・LCP)への影響を常に意識して設計してください。