本文へスキップ
T2R tech2rich.com
Web開発 🔤 CSS 📚 モダンCSS入門 第2回 #CSS #モダンCSS #レスポンシブ #フロントエンド

【モダンCSS入門 第2回】コンテナクエリ完全入門 — 親要素の幅でレスポンシブする新常識

ビューポート幅ではなく『親要素の幅』に応じてスタイルを切り替える @container クエリ。同じカードコンポーネントを画面幅ではなく置き場所で出し分ける実例で、レスポンシブデザインの新常識を解説します。

📅 公開: 2026.05.20 ⏱ 読了 約7分 ✍ 管理人

「同じカードコンポーネントなのに、サイドバーに置くと崩れる…」

レスポンシブデザインを書いていて、必ずぶつかるこの悩み。これまで CSS のメディアクエリは 「画面(ビューポート)の幅」 しか見られず、コンポーネントが置かれた 「コンテナの幅」 には反応できませんでした。

それを解決するのが CSS コンテナクエリ(@container) です。置き場所のサイズに応じてコンポーネントが自分の見た目を切り替える、本物の「コンポーネント駆動レスポンシブ」が実現できます。

この記事では、コンテナクエリの基本から、実プロジェクトですぐ使える設計パターンまでを解説します。

先輩

この記事のゴール

コンテナクエリで container-type@container を使い分け、同じコンポーネントを置き場所ごとに自然に変化させる具体的な書き方を身につけます。

メディアクエリの何が困るのか

これまでのメディアクエリは「画面幅」基準でした。

/* ❌ 画面幅でしか判定できない */
@media (min-width: 640px) {
  .card { display: grid; grid-template-columns: 120px 1fr; }
}

このカードを 「画面幅640px以上」 ではなく、「サイドバー(幅280px)に置かれているとき」 に1カラム表示にしたい、というのは従来不可能でした。

カードはどこに置かれても見た目を変えたいのに、CSS には「自分が置かれた場所」を知る術がなかったのです。

コンテナクエリの基本

コンテナクエリは、2段階で使います。

  1. 「コンテナ」として宣言したい要素container-type を指定
  2. その中の要素には @containerコンテナ幅に応じたスタイル を書く
<div class="card-wrapper">
  <div class="card">
    <img src="..." alt="..." />
    <h3>カードのタイトル</h3>
    <p>説明文…</p>
  </div>
</div>
/* 1. このラッパーを「コンテナ」として宣言 */
.card-wrapper {
  container-type: inline-size;
}

/* 2. コンテナ幅が 480px 以上のときだけ横並びに */
@container (min-width: 480px) {
  .card {
    display: grid;
    grid-template-columns: 120px 1fr;
    gap: 16px;
  }
}

ポイントは container-type: inline-size。これで「横方向のサイズ(=幅)」を監視対象にする宣言になります。

実用パターン1: サイドバーと本文で同じカードを使う

コンテナクエリの真価が出る、もっとも分かりやすい例です。

<main class="layout">
  <section class="main-content">
    <article class="card">…</article>   <!-- 広いので横並び表示 -->
  </section>
  <aside class="sidebar">
    <article class="card">…</article>   <!-- 狭いので縦並び表示 -->
  </aside>
</main>
.main-content,
.sidebar {
  container-type: inline-size;
}

.card {
  display: flex;
  flex-direction: column;  /* 狭いときは縦並び(デフォルト) */
}

@container (min-width: 400px) {
  .card {
    flex-direction: row;   /* 広いコンテナでは横並び */
    align-items: center;
  }
}

HTMLもCSSも1セットで済むのがミソです。コンポーネントを再利用するたびに「ここはsidebar用」「ここはmain用」と分ける必要がなくなります。

実用パターン2: コンテナに名前をつけて狙い撃ち

複数のコンテナがネストしている場面では、container-nameどのコンテナを基準にするかを指定できます。

.page-grid {
  container-type: inline-size;
  container-name: layout;     /* このコンテナに名前を付与 */
}

.card-list {
  container-type: inline-size;
  container-name: cards;
}

/* layout コンテナの幅にだけ反応 */
@container layout (min-width: 768px) {
  .header { padding: 32px; }
}

/* cards コンテナの幅にだけ反応 */
@container cards (min-width: 320px) {
  .card { border-radius: 12px; }
}

ネストしたレイアウトでも 意図しない上位コンテナに反応してしまう事故 を防げます。

実用パターン3: コンテナクエリ単位 (cqi / cqb)

vwvh のコンテナクエリ版もあります。

単位意味
cqwコンテナ幅の 1%
cqhコンテナ高さの 1%
cqiコンテナのインライン方向 1%(横書きなら幅)
cqbコンテナのブロック方向 1%(横書きなら高さ)
.card-wrapper {
  container-type: inline-size;
}

.card-title {
  /* コンテナ幅に応じて文字サイズが伸縮する */
  font-size: clamp(1rem, 5cqi, 1.75rem);
}

clamp() と組み合わせれば、コンテナのサイズに対して滑らかにスケールする文字 が、メディアクエリのブレークポイントなしで実現できます。

ブラウザ対応

コンテナクエリは 2023年2月にすべての主要ブラウザでサポートされ、Baseline 2023 に到達しています。2026年現在、安心して本番利用できます。

不安な場合は @supports でフォールバックを書けます。

@supports (container-type: inline-size) {
  .card-wrapper { container-type: inline-size; }

  @container (min-width: 480px) {
    .card { display: grid; }
  }
}

つまずきやすいポイント

注意

⚠ ここは要注意

container-type: inline-size を指定した要素は 幅を子要素から決められなくなります(コンテナ自身は親基準)。意図せず横幅が広がる事故に注意。

メディアクエリとの使い分け

判定軸何を使う?
画面全体のレイアウトメディアクエリナビをハンバーガーに切替 / サイドバーを表示/非表示
コンポーネントの内部コンテナクエリカードを縦並び ⇄ 横並び / 文字サイズの調整
ユーザー環境(ダークモード等)メディアクエリprefers-color-scheme
印刷スタイルメディアクエリ@media print

両者は 競合するものではなく、補完しあう関係 です。

まとめ

CSS コンテナクエリを使うと、以下が実現できます。

特に デザインシステムコンポーネントライブラリ を作るときは、コンテナクエリ前提で設計するだけで「再利用したら崩れる」事故が激減します。

💡 次回は :is():where() を取り上げます。重複セレクタを1つにまとめる強力な擬似クラスで、特異性(specificity)の落とし穴も含めて解説します。

関連の技術記事