はじめに:94%がサポート済みなのに、なぜ使われないのか
CSSコンテナクエリは現在、ブラウザサポート率が約94%に達しています。しかしState of CSSの調査によると、開発者の86%が存在を認知しているにもかかわらず、実際に使用しているのは**41.4%**にとどまります。
なぜこのような乖離が生まれるのでしょうか。理由はシンプルです。コンテナクエリの文法がメディアクエリと酷似しているからです。見た目が似ているため「用途も似ているはず」と誤解されやすいのですが、両者は参照する方向が真逆です。
本記事では、メディアクエリとコンテナクエリの根本的な違いを整理し、実務でコンポーネントをどう設計すべきかをコードで確認します。(根拠資料:Smashing Magazine 原文)

本質的な違い:メディアクエリは「外」を、コンテナクエリは「内」を見る
メディアクエリの限界
以下のコードをご覧ください。
@media (min-width: 1024px) {
.card {
display: flex;
}
}
このコードはブラウザに対して、**「現在のビューポート幅はいくつか」**という一点だけを問い合わせています。
問題は、この .card が1920pxのデスクトップ画面内にある300pxのグリッドセルに配置された場合に発生します。ビューポートは依然として1920pxなので min-width: 1024px が発火し、幅300pxしかないカードに display: flex が適用されてレイアウトが崩壊します。
「メディアクエリは賢くない。概念が悪いのではなく、知っている情報が少なすぎるのだ」 — Kevin Powell
コンテナクエリに置き換えると
/* 親要素をコンテナとして登録 */
.card-wrapper {
container-name: card;
container-type: inline-size;
}
/* 親のインライン(横方向)サイズを基準に判定 */
@container card (min-width: 450px) {
.card {
display: flex;
flex-direction: row;
}
}
これでカードはビューポートを気にしません。**「親ラッパーが450px以上の横方向スペースを確保しているか」**だけを判定します。条件を満たせば横並び、満たさなければデフォルトの block 配置です。
実践例:ビューポートではなくコンポーネントに追従する流体タイポグラフィ
メディアクエリ時代は vw 単位でフォントサイズを調整していました。
/* ❌ ビューポート基準 — サイドバーに入れるとフォントが破綻 */
.card-title {
font-size: clamp(100%, 1rem + 2vw, 24px);
}
コンテナクエリには専用の単位(cqi、cqw、cqb)があります。clamp() と組み合わせることで、コンポーネントサイズに応じた流体タイポグラフィが実現できます。
/* ✅ コンテナのインラインサイズ基準 */
.card-title {
font-size: clamp(1rem, .5rem + 3cqi, 2rem);
}
これでカードをどこに配置しても、フォントは自身のコンテナ内で最適化されます。
![]()
注意点:コンテナクエリの3つの副作用
導入前に必ず把握しておくべき落とし穴があります。
1. コンテナは自身をクエリできない
/* ❌ 無限ループ — 動作しない */
.card {
container-name: card;
container-type: inline-size;
}
@container card (min-width: 400px) {
.card { display: flex; }
}
コンテナが自身のサイズを見て自身を変更すると無限ループになるため、ブラウザがこれを禁止しています。必ず親ラッパーを1段追加し、そのラッパーをコンテナとして登録する必要があります。マークアップが1階層増えるトレードオフがあります。
2. container-type: size はレイアウトを崩壊させる可能性がある
/* ⚠️ 高さを明示しないと0pxに崩壊 */
.hero-banner {
container-type: size;
}
size は縦横両方をクエリ対象にする指定ですが、ブラウザは子要素を参照せずにコンテナサイズを計算します。height や aspect-ratio を明示しないと高さが0になります。特別な理由がない限り、inline-size のみを使うのが安全です。
3. カスタムプロパティはクエリ条件に使用できない
:root { --breakpoint-lg: 1600px; }
/* ❌ 動作しない */
@container (min-width: var(--breakpoint-lg)) { /* ... */ }
カスタムプロパティはDOMを辿ってカスケードされる値であるため、クエリ条件内でその値が再度変化する可能性があります。ブラウザは循環参照を防ぐため、条件部での使用を禁止しています。ブレークポイントを変数管理していたチームには不便な仕様です。
どちらを使うべきか — マクロ vs ミクロ
- メディアクエリ(マクロレイアウト): ページ全体構造、ヘッダー/フッター、メイングリッド、
prefers-color-scheme、タッチスクリーン判定 - コンテナクエリ(ミクロレイアウト): カード、ウィジェット、フォーム、ナビゲーションなど複数コンテキストで再利用されるコンポーネント
判断基準はシンプルです。**「このコンポーネントは1箇所でしか使われないか」ならメディアクエリ、「複数レイアウトで再利用されるか」**ならコンテナクエリです。

まとめ:ビューポートはあくまで「代理指標」にすぎない
これまでのレスポンシブデザインは、ビューポート幅という代理指標(proxy)に依存してきました。しかしモダンWebには2,300以上ものビューポートサイズが存在します。それをすべて想定するのは不可能です。
コンテナクエリは、レスポンシブデザインの基準を**「画面」から「コンポーネントの実際のスペース」へ**移行させます。これこそが本質的に正しい方向性です。
日本の開発エコシステムにおける適用文脈
日本の受託開発やSaaS開発では、デザインシステムや共通コンポーネントライブラリを運用するチームにとって特に有効です。ただし以下の2点は事前に確認してください。
- レガシーブラウザ対応: 94%のサポート率は優秀ですが、官公庁系や金融系プロジェクトで旧Edge対応が必要な場合は、
@supportsによる分岐が必須です。 - マークアップのラッパー増加: コンテナは自身をクエリできないため、ラッパー
<div>が1つ増えます。HTMLコーダーと分業する現場では、マークアップ規約を事前に合意しておくと安全です。
次のステップ学習方向
- Container Style Queries: 計算済みスタイルに反応する次世代機能(現在実験段階)
:has()セレクタとの組み合わせ: 親の状態に応じた条件付きスタイリング- CSS Nesting +
@container: コンポーネント単位のCSSカプセル化パターン
あわせて読みたい記事
- マークダウンパースを、フレームワークに依存せずどこでも使う(Astro, React, Vue, Svelte) — コンポーネント再利用性の観点で併読をおすすめします。
- AWS欧州主権クラウド、クロスパーティション障害復旧設計のすべて — インフラ層における「コンテキスト適応型」設計の事例です。