【CSS】コンテナクエリとは:使い方やメディアクエリとの違い・CSS変数

css-container
ポートフォリオ向けサーバー
HTML/CSSスキルが活きる!
学んだ知識を活かして、
自分だけのブログを始めませんか?

WordPressブログなら、あなたのコーディング知識でデザインのカスタマイズが自由自在。
ブログデビューに最適な初心者向けサーバー環境を徹底比較しました。

CSSのコンテナクエリ(@container)は、画面幅(ビューポート)ではなく「親要素(コンテナ)の幅」に合わせてレイアウトを切り替える機能です。

本記事では、メディアクエリの限界を突破するコンポーネント指向の実装方法、必須のcontainer-typeの指定、単位cqwの使い方まで解説します。

HTML/CSS学習者の方へ
「学んだコード、自分のブログで試してみませんか?」
多くのブロガーがデザインでつまずく中、コードが読めるあなたは圧倒的に有利です。
自由自在なサイト構築の第一歩となる、初心者向けサーバーを分かりやすく比較しました。

\ スキルを活かして情報発信 / ブログ向けレンタルサーバー4選を読む▶︎
目次

コンテナクエリとは:メディアクエリとの違い

これまで、レスポンシブデザインと言えば画面サイズ(ビューポート)を基準にするメディアクエリでした。

しかし、コンテナクエリを一言で表すなら、「画面幅ではなく、親要素(入れ物)の幅に合わせてデザインを切り替える技術」です。

ここでは、メディアクエリとの違い、コンテナクエリがWeb制作の現場で必須になりつつあるのかをサンプルと共に解説します。

コンテナクエリとは:メディアクエリとの違い
  • 画面幅ではなく親要素の幅で判定する仕様
  • コンテナクエリが必要なのか?コンポーネント指向との相性

メディアクエリの使い方を詳しく知りたい人は「【CSS】メディアクエリの書き方:レスポンシブ対応・ブレイクポイント・複数指定・効かない対策」を一読ください。

画面幅ではなく親要素の幅で判定する仕様

従来のメディアクエリ(@media)は、「ブラウザの画面幅が768px以上なら」というように、常に画面全体を基準にしていました。

一方、コンテナクエリ(@container)は、「自分の親要素(コンテナ)の幅が400px以上なら」というように、自分が包まれている箱のサイズを基準にしてスタイルを切り替えます。

コンテナクエリを使う際は、「切り替えたい要素に@containerを書く前に、直接の親要素にcontainer-type: inline-size;を設定すること」です。

⭕️ 右下をドラッグして箱の幅を変えてみよう!箱のサイズだけでレイアウトが変わる!

画像
コンテナクエリの使い方

このカードは画面幅ではなく、外側の点線の箱(親要素)の幅が「400px以上」になった時だけ横並びに変化します!

/* ⭕️ 親要素(入れ物)に「あなたが基準だぞ」と教える! */
.container-box {
  container-type: inline-size; /* 🚨 これがないとコンテナクエリは絶対に動かない! */
}

/* ⭕️ 画面幅(@media)ではなく、親の幅(@container)で判定する! */
@container (min-width: 400px) {
  .card {
    flex-direction: row; /* 💡 親の幅が400pxを超えた時「だけ」横並びになる! */
  }
}
HTMLコード表示
<div class="cq-basic-wrapper">
  
  <p class="cq-basic-caption">⭕️ 右下をドラッグして箱の幅を変えてみよう!箱のサイズだけでレイアウトが変わる!</p>

  <div class="cq-basic-demo-area">
    <!-- 💡 基準となる親要素(コンテナ) -->
    <div class="cq-container-box">
      
      <!-- 変化する子要素(カード) -->
      <div class="cq-card">
        <div class="cq-card-image">
          画像
        </div>
        <div class="cq-card-content">
          <div class="cq-card-title">コンテナクエリの使い方</div>
          <p class="cq-card-desc">
            このカードは画面幅ではなく、外側の点線の箱(親要素)の幅が「400px以上」になった時だけ横並びに変化します!
          </p>
        </div>
      </div>

    </div>
  </div>

  <!-- 💡 コード解説エリア -->
  <div class="cq-basic-code-area">
    <span class="hl-comment">/* ⭕️ 親要素(入れ物)に「あなたが基準だぞ」と教える! */</span><br>
    <span class="hl-blue">.container-box</span> {<br>
      <span class="hl-green">container-type:</span> <span class="hl-red">inline-size;</span> <span class="hl-comment">/* 🚨 これがないとコンテナクエリは絶対に動かない! */</span><br>
    }<br><br>

    <span class="hl-comment">/* ⭕️ 画面幅(@media)ではなく、親の幅(@container)で判定する! */</span><br>
    <span class="hl-blue">@container (min-width: 400px)</span> {<br>
      <span class="hl-blue">.card</span> {<br>
        <span class="hl-green">flex-direction:</span> <span class="hl-red">row;</span> <span class="hl-comment">/* 💡 親の幅が400pxを超えた時「だけ」横並びになる! */</span><br>
      }<br>
    }
  </div>

</div>
CSSコード表示
.cq-basic-wrapper {
  background-color: #f8f9fa;
  padding: 30px;
  border-radius: 8px;
  border: 1px solid #dee2e6;
}

.cq-basic-caption {
  font-size: 14px;
  font-weight: bold;
  margin-bottom: 20px;
  color: #198754;
  text-align: center;
}

.cq-basic-demo-area {
  background-color: #e9ecef;
  padding: 30px 20px;
  border-radius: 8px;
  border: 1px dashed #adb5bd;
  margin-bottom: 20px;
}

/* === 💡 1. コンテナ(親要素)の定義 === */
.cq-container-box {
  /* ここが最も重要!この要素の幅を基準にすることを宣言する */
  container-type: inline-size;
  
  /* デモ用:ドラッグで幅を変えられるようにする設定 */
  resize: horizontal;
  overflow: hidden;
  max-width: 100%;
  min-width: 250px;
  width: 300px; /* 初期値は狭め(縦並びになる幅) */
  
  /* 見た目の装飾 */
  background-color: #fff;
  padding: 20px;
  border-radius: 8px;
  border: 2px dashed #0d6efd;
  margin: 0 auto;
  position: relative;
}

/* つまみを分かりやすくするための疑似要素(装飾) */
.cq-container-box::after {
  content: "↔ ドラッグして幅を変更";
  position: absolute;
  bottom: 0;
  right: 15px;
  font-size: 11px;
  color: #0d6efd;
  font-weight: bold;
  pointer-events: none;
}

/* === 💡 2. カード(子要素)のベース設定(狭い時用) === */
.cq-card {
  background-color: #f8f9fa;
  border-radius: 8px;
  border: 1px solid #ced4da;
  overflow: hidden;
  display: flex;
  flex-direction: column; /* ベースは縦並び */
}

.cq-card-image {
  background-color: #0d6efd;
  color: #fff;
  display: flex;
  align-items: center;
  justify-content: center;
  font-weight: bold;
  height: 120px;
  width: 100%;
}

.cq-card-content {
  padding: 15px;
}

.cq-card-title {
  margin-top: 0;
  margin-bottom: 10px;
  font-size: 16px;
  color: #333;
}

.cq-card-desc {
  margin: 0;
  font-size: 13px;
  color: #6c757d;
  line-height: 1.5;
}

/* === 💡 3. コンテナクエリの指定(箱が広い時用) === */
/* 親要素(cq-container-box)の幅が400px以上になったら発動! */
@container (min-width: 400px) {
  .cq-card {
    flex-direction: row; /* 横並びに変更 */
  }
  
  .cq-card-image {
    width: 150px; /* 画像の幅を固定 */
    height: auto;
    min-height: 120px;
  }
  
  .cq-card-content {
    flex: 1; /* 残りの幅をテキストエリアが埋める */
    display: flex;
    flex-direction: column;
    justify-content: center;
  }
}

/* =コード解説エリア= */
.cq-basic-code-area {
  background-color: #282c34;
  color: #abb2bf;
  padding: 20px;
  border-radius: 6px;
  font-family: monospace;
  font-size: 13px;
  line-height: 1.6;
  border-left: 4px solid #0d6efd;
  overflow-x: auto;
  text-align: left;
}

.hl-blue { color: #61afef; font-weight: bold; }
.hl-red { color: #e06c75; font-weight: bold; }
.hl-green { color: #98c379; font-weight: bold; }
.hl-comment { color: #6c757d; font-style: italic; }

コンテナクエリが必要なのか?コンポーネント指向との相性

「画面幅のメディアクエリがあれば十分じゃないの?」と思うかもしれません。

しかし、現代のWeb制作(React、Vue、WordPressのブロックエディタなど)は、ボタンやカードなどの部品を使い回す「コンポーネント指向」が主流です。

ここで大問題が発生します。

同じカードコンポーネントを広いメインエリアに置く場合と狭いサイドバーに置く場合を想像してください。

メディアクエリだとPC画面で見た時、メインエリアのカードもサイドバーのカードも「今はPC画面だから横並びだ!」と一斉に同じ形になってしまい、狭いサイドバーの中でレイアウトが崩壊します。

コンポーネントを設計する際は、「メディアクエリへの依存を捨て、コンテナクエリで自己完結させること」です。

コンポーネント自身に「自分が置かれた箱の幅が広ければ横並び、狭ければ縦並びになる」という性質を持たせることで、どこに配置しても崩れない部品が完成します。

⭕️ 全く同じHTMLコードなのに、置かれた場所の広さに合わせて勝手に変形する!

メインエリア(広い)
画像
同じカード部品です

広い場所に置かれたので、自ら判断して「横並び」に展開しています。

サイドバー(狭い)
画像
同じカード部品です

狭い場所に置かれたので、はみ出さないよう「縦並び」をキープします。

/* ❌ 旧来の書き方(メディアクエリの限界と保守地獄) */
.sidebar .card {
  flex-direction: column; /* 🚨 置く場所が変わるたびに専用のクラスを書くハメになる */
}

/* ⭕️ コンテナクエリによるコンポーネントの自己適応化! */
.main-area, .sidebar-area {
  container-type: inline-size; /* 💡 置き場所となるそれぞれの「箱」をコンテナ化する */
}

/* カード部品のCSS(これだけ書いておけばどこに置かれても絶対に崩れない!) */
@container (min-width: 400px) {
  .comp-card {
    flex-direction: row; /* 💡 カード自身が親の幅を判断して、自ら最適な形に変形する! */
  }
}
HTMLコード表示
<div class="cq-comp-wrapper">
  
  <p class="cq-comp-caption">⭕️ 全く同じHTMLコードなのに、置かれた場所の広さに合わせて勝手に変形する!</p>

  <div class="cq-comp-demo-area">
    <!-- ページ全体のレイアウト(メイン + サイドバー) -->
    <div class="cq-layout-grid">
      
      <!-- 💡 メインエリア(広いコンテナ) -->
      <div class="cq-main-area">
        <div class="area-title">メインエリア(広い)</div>
        
        <!-- ★使い回すカード部品(HTMLは全く同じ!) -->
        <div class="cq-comp-card">
          <div class="comp-card-img">画像</div>
          <div class="comp-card-body">
            <div class="comp-card-title">同じカード部品です</div>
            <p class="comp-card-txt">広い場所に置かれたので、自ら判断して「横並び」に展開しています。</p>
          </div>
        </div>
        
      </div>

      <!-- 💡 サイドバーエリア(狭いコンテナ) -->
      <div class="cq-sidebar-area">
        <div class="area-title">サイドバー(狭い)</div>
        
        <!-- ★使い回すカード部品(HTMLは全く同じ!) -->
        <div class="cq-comp-card">
          <div class="comp-card-img">画像</div>
          <div class="comp-card-body">
            <div class="comp-card-title">同じカード部品です</div>
            <p class="comp-card-txt">狭い場所に置かれたので、はみ出さないよう「縦並び」をキープします。</p>
          </div>
        </div>
        
      </div>

    </div>
  </div>

  <!-- 💡 追加:コード解説エリア -->
  <div class="cq-comp-code-area">
    <span class="hl-comment">/* ❌ 旧来の書き方(メディアクエリの限界と保守地獄) */</span><br>
    <span class="hl-blue">.sidebar .card</span> {<br>
      <span class="hl-green">flex-direction:</span> <span class="hl-red">column;</span> <span class="hl-comment">/* 🚨 置く場所が変わるたびに専用のクラスを書くハメになる */</span><br>
    }<br><br>

    <span class="hl-comment">/* ⭕️ コンテナクエリによるコンポーネントの自己適応化! */</span><br>
    <span class="hl-blue">.main-area, .sidebar-area</span> {<br>
      <span class="hl-green">container-type:</span> <span class="hl-red">inline-size;</span> <span class="hl-comment">/* 💡 置き場所となるそれぞれの「箱」をコンテナ化する */</span><br>
    }<br>
    <br>
    <span class="hl-comment">/* カード部品のCSS(これだけ書いておけばどこに置かれても絶対に崩れない!) */</span><br>
    <span class="hl-blue">@container (min-width: 400px)</span> {<br>
      <span class="hl-blue">.comp-card</span> {<br>
        <span class="hl-green">flex-direction:</span> <span class="hl-red">row;</span> <span class="hl-comment">/* 💡 カード自身が親の幅を判断して、自ら最適な形に変形する! */</span><br>
      }<br>
    }
  </div>

</div>
CSSコード表示
.cq-comp-wrapper {
  background-color: #f8f9fa;
  padding: 30px;
  border-radius: 8px;
  border: 1px solid #dee2e6;
}

.cq-comp-caption {
  font-size: 14px;
  font-weight: bold;
  margin-bottom: 20px;
  color: #198754;
  text-align: center;
}

.cq-comp-demo-area {
  background-color: #fff;
  padding: 20px;
  border-radius: 8px;
  border: 1px dashed #adb5bd;
  margin-bottom: 20px;
}

/* ページ全体のグリッドレイアウト(PCで見ると横並びになる想定) */
.cq-layout-grid {
  display: grid;
  gap: 20px;
  /* メインエリアを広く、サイドバーを狭く固定 */
  grid-template-columns: 2fr 1fr; 
}

/* 狭い画面(スマホなど)では縦に積む */
@media (max-width: 767px) {
  .cq-layout-grid {
    grid-template-columns: 1fr;
  }
}

.area-title {
  font-size: 15px;
  margin-top: 0;
  margin-bottom: 15px;
  color: #495057;
  border-bottom: 2px solid #ced4da;
  padding-bottom: 5px;
}

/* === 💡 1. 各配置エリアを「コンテナ」として定義する === */
.cq-main-area {
  background-color: #e2e3e5;
  padding: 20px;
  border-radius: 8px;
  /* メインエリアをコンテナ化 */
  container-type: inline-size;
}

.cq-sidebar-area {
  background-color: #e2e3e5;
  padding: 20px;
  border-radius: 8px;
  /* サイドバーエリアもコンテナ化 */
  container-type: inline-size;
}

/* === 💡 2. 使い回すコンポーネント(カード)の設計 === */
.cq-comp-card {
  background-color: #fff;
  border-radius: 6px;
  border: 1px solid #adb5bd;
  overflow: hidden;
  display: flex;
  flex-direction: column; /* ベースはどこに置かれても安全な縦並び */
}

.comp-card-img {
  background-color: #ffc107;
  color: #333;
  display: flex;
  align-items: center;
  justify-content: center;
  font-weight: bold;
  height: 100px;
  width: 100%;
}

.comp-card-body {
  padding: 15px;
}

.comp-card-title {
  margin-top: 0;
  margin-bottom: 8px;
  font-size: 15px;
  color: #333;
}

.comp-card-txt {
  margin: 0;
  font-size: 12px;
  color: #6c757d;
  line-height: 1.5;
}

/* === 💡 3. コンポーネント自身が持つコンテナクエリ === */
/* 「自分が包まれている箱の幅」が 400px 以上なら横並びに変形する! */
/* (※これにより、広いメインエリアでのみ発動し、サイドバーでは発動しない) */
@container (min-width: 400px) {
  .cq-comp-card {
    flex-direction: row;
  }
  
  .comp-card-img {
    width: 120px;
    height: auto;
    min-height: 100px;
  }
  
  .comp-card-body {
    flex: 1;
    display: flex;
    flex-direction: column;
    justify-content: center;
  }
}

/* =コード解説エリア= */
.cq-comp-code-area {
  background-color: #282c34;
  color: #abb2bf;
  padding: 20px;
  border-radius: 6px;
  font-family: monospace;
  font-size: 13px;
  line-height: 1.6;
  border-left: 4px solid #0d6efd;
  overflow-x: auto;
  text-align: left;
}

.hl-blue { color: #61afef; font-weight: bold; }
.hl-red { color: #e06c75; font-weight: bold; }
.hl-green { color: #98c379; font-weight: bold; }
.hl-comment { color: #6c757d; font-style: italic; }

コンテナクエリの基本的な使い方と書き方

コンテナクエリの概念を理解したところで、具体的なコンテナ クエリの使い方 に入ります。

書き方自体は、従来のメディアクエリ(@media)を知っていれば簡単です。

ここでは、コンテナクエリを動作させる2つの必須ステップと複雑なレイアウトを制御する「名前付きコンテナ」の実践的な使い方を解説します。

コンテナクエリの基本的な使い方と書き方
  • 親要素をコンテナとして定義する
  • @containerを使って条件ごとのスタイルを書く
  • 名前付きコンテナによる詳細な制御

親要素をコンテナとして定義する

コンテナクエリを使うための絶対条件は「基準となる親要素はどれなのかを、ブラウザに明示すること」です。

これを指定するのがcontainer-typeプロパティです。

通常は、横幅を基準にするinline-sizeを指定します。

基準を定義するには、「コンポーネントを設計する際、外側に『コンテナ用の透明なラッパー(親要素)』を1枚噛ませ、そこにcontainer-type: inline-size;を指定すること」です。

⭕️ 親要素に「お前が基準(コンテナ)だ!」と宣言しろ!

📦 コンテナ(親要素:container-type指定あり)

僕(子要素)は、外側の箱(親要素)の幅を監視しています!

/* ❌ 罠:変化させたい子要素に書いてしまう */
.child-fail {
  container-type: inline-size; /* 🚨 自分のサイズは見れないのでエラーになる */
}

/* ⭕️ 子を包む「親」に指定する! */
.step1-container {
  container-type: inline-size; /* 💡 この箱の「横幅」を基準にすることを宣言 */
}
HTMLコード表示
<div class="cq-step1-wrapper">
  
  <p class="cq-step1-caption">⭕️ 親要素に「お前が基準(コンテナ)だ!」と宣言しろ!</p>

  <div class="cq-step1-demo-area">
    
    <!-- 💡 これがコンテナ(基準となる親要素) -->
    <div class="step1-container">
      <p class="container-label">📦 コンテナ(親要素:container-type指定あり)</p>
      
      <!-- 変化する中身(子要素) -->
      <div class="step1-child">
        <p class="child-text">
          僕(子要素)は、外側の箱(親要素)の幅を監視しています!
        </p>
      </div>
      
    </div>

  </div>

  <div class="cq-step1-code-area">
    <span class="hl-comment">/* ❌ 罠:変化させたい子要素に書いてしまう */</span><br>
    <span class="hl-blue">.child-fail</span> {<br>
      <span class="hl-green">container-type:</span> <span class="hl-red">inline-size;</span> <span class="hl-comment">/* 🚨 自分のサイズは見れないのでエラーになる */</span><br>
    }<br><br>

    <span class="hl-comment">/* ⭕️ 子を包む「親」に指定する! */</span><br>
    <span class="hl-blue">.step1-container</span> {<br>
      <span class="hl-green">container-type:</span> <span class="hl-red">inline-size;</span> <span class="hl-comment">/* 💡 この箱の「横幅」を基準にすることを宣言 */</span><br>
    }
  </div>

</div>
CSSコード表示
.cq-step1-wrapper {
  background-color: #f8f9fa;
  padding: 30px;
  border-radius: 8px;
  border: 1px solid #dee2e6;
}

.cq-step1-caption {
  font-size: 14px;
  font-weight: bold;
  margin-bottom: 20px;
  color: #198754;
  text-align: center;
}

.cq-step1-demo-area {
  background-color: #e9ecef;
  padding: 30px 20px;
  border-radius: 8px;
  border: 1px dashed #adb5bd;
  margin-bottom: 20px;
}

/* === 💡 コンテナ(親要素)の定義 === */
.step1-container {
  /* 👇 これが必須の魔法の1行 👇 */
  container-type: inline-size;
  
  /* 以下はデモ用の装飾 */
  background-color: #fff;
  border: 4px dashed #0d6efd; /* 分かりやすい青い破線 */
  padding: 20px;
  border-radius: 8px;
  position: relative;
  
  /* ドラッグして幅を変えられるようにする */
  resize: horizontal;
  overflow: hidden;
  max-width: 100%;
  min-width: 200px;
}

.step1-container::after {
  content: "↔ ドラッグ可能";
  position: absolute;
  bottom: 0;
  right: 15px;
  font-size: 11px;
  color: #0d6efd;
  font-weight: bold;
}

.container-label {
  margin-top: 0;
  margin-bottom: 15px;
  font-size: 14px;
  font-weight: bold;
  color: #0d6efd;
}

/* === 子要素の装飾 === */
.step1-child {
  background-color: #ffc107;
  padding: 15px;
  border-radius: 6px;
  border: 2px solid #fd7e14;
}

.child-text {
  margin: 0;
  font-size: 13px;
  font-weight: bold;
  color: #333;
}

/* =コード解説エリア= */
.cq-step1-code-area {
  background-color: #282c34;
  color: #abb2bf;
  padding: 20px;
  border-radius: 6px;
  font-family: monospace;
  font-size: 13px;
  line-height: 1.6;
  border-left: 4px solid #0d6efd;
  overflow-x: auto;
  text-align: left;
}

.hl-blue { color: #61afef; font-weight: bold; }
.hl-red { color: #e06c75; font-weight: bold; }
.hl-green { color: #98c379; font-weight: bold; }
.hl-comment { color: #6c757d; font-style: italic; }

@containerを使って条件ごとのスタイルを書く

親要素をコンテナとして定義したら、次は条件分岐を書きます。

メディアクエリの@media (min-width: ...)と全く同じ感覚で、@container (min-width: ...)と記述するだけです。

クエリを書く際は、「@containerの中では『コンテナの中にある子要素や孫要素』のスタイルだけを変更し、コンテナ自身のスタイルはいじらないこと」です。

⭕️ 箱を広げてみよう!親の幅が400pxを超えるとレイアウトが横に並ぶ!

写真

親の幅で変化するUI

📱 現在:狭い(縦並び)

💻 現在:広い(横並び)

/* ❌ 罠:コンテナ自身を操作しようとする */
@container (min-width: 400px) {
  .step2-container { /* 🚨 親自身をいじるのはバグの元なのでNG */
    background-color: red;
  }
}

/* ⭕️ コンテナの中にある「子要素」のレイアウトを切り替える! */
@container (min-width: 400px) {
  .step2-card {
    display: flex;
    flex-direction: row; /* 💡 400px以上で横並びに! */
  }
}
HTMLコード表示
<div class="cq-step2-wrapper">
  
  <p class="cq-step2-caption">⭕️ 箱を広げてみよう!親の幅が400pxを超えるとレイアウトが横に並ぶ!</p>

  <div class="cq-step2-demo-area">
    
    <!-- 💡 コンテナ(基準となる親要素) -->
    <div class="step2-container">
      
      <!-- 変化させたい子要素たち -->
      <div class="step2-card">
        <div class="step2-image">写真</div>
        <div class="step2-body">
          <p class="step2-title">親の幅で変化するUI</p>
          <p class="step2-status is-narrow">📱 現在:狭い(縦並び)</p>
          <p class="step2-status is-wide">💻 現在:広い(横並び)</p>
        </div>
      </div>
      
    </div>

  </div>

  <div class="cq-step2-code-area">
    <span class="hl-comment">/* ❌ 罠:コンテナ自身を操作しようとする */</span><br>
    <span class="hl-blue">@container (min-width: 400px)</span> {<br>
      <span class="hl-blue">.step2-container</span> { <span class="hl-comment">/* 🚨 親自身をいじるのはバグの元なのでNG */</span><br>
        <span class="hl-green">background-color:</span> <span class="hl-red">red;</span><br>
      }<br>
    }<br><br>

    <span class="hl-comment">/* ⭕️ コンテナの中にある「子要素」のレイアウトを切り替える! */</span><br>
    <span class="hl-blue">@container (min-width: 400px)</span> {<br>
      <span class="hl-blue">.step2-card</span> {<br>
        <span class="hl-green">display:</span> <span class="hl-red">flex;</span><br>
        <span class="hl-green">flex-direction:</span> <span class="hl-red">row;</span> <span class="hl-comment">/* 💡 400px以上で横並びに! */</span><br>
      }<br>
    }
  </div>

</div>
CSSコード表示
.cq-step2-wrapper {
  background-color: #f8f9fa;
  padding: 30px;
  border-radius: 8px;
  border: 1px solid #dee2e6;
}

.cq-step2-caption {
  font-size: 14px;
  font-weight: bold;
  margin-bottom: 20px;
  color: #198754;
  text-align: center;
}

.cq-step2-demo-area {
  background-color: #e9ecef;
  padding: 30px 20px;
  border-radius: 8px;
  border: 1px dashed #adb5bd;
  margin-bottom: 20px;
}

/* === 💡 1. コンテナの定義 === */
.step2-container {
  container-type: inline-size;
  
  background-color: #fff;
  border: 4px dashed #0d6efd;
  padding: 20px;
  border-radius: 8px;
  resize: horizontal;
  overflow: hidden;
  max-width: 100%;
  width: 250px; /* 初期状態(狭い) */
  margin: 0 auto;
  position: relative;
}

.step2-container::after {
  content: "↔ ドラッグ";
  position: absolute;
  bottom: 0;
  right: 15px;
  font-size: 11px;
  color: #0d6efd;
  font-weight: bold;
}

/* === 💡 2. 子要素(カード)のベース設計 === */
.step2-card {
  background-color: #f8f9fa;
  border-radius: 6px;
  border: 1px solid #ced4da;
  display: flex;
  flex-direction: column; /* ベースは縦並び */
  overflow: hidden;
}

.step2-image {
  background-color: #6c757d;
  color: #fff;
  display: flex;
  align-items: center;
  justify-content: center;
  font-weight: bold;
  height: 100px;
  width: 100%;
  transition: background-color 0.3s;
}

.step2-body {
  padding: 15px;
}

.step2-title {
  margin-top: 0;
  margin-bottom: 10px;
  font-weight: bold;
  font-size: 15px;
}

/* ステータステキストの初期状態 */
.step2-status {
  margin: 0;
  font-size: 13px;
  font-weight: bold;
  padding: 5px 10px;
  border-radius: 4px;
}
.is-narrow {
  background-color: #dc3545;
  color: #fff;
  display: block;
}
.is-wide {
  background-color: #198754;
  color: #fff;
  display: none;
}

/* === 💡 3. コンテナクエリの指定 === */
@container (min-width: 400px) {
  
  .step2-card {
    flex-direction: row; /* 横並びに変更 */
  }
  
  .step2-image {
    width: 120px;
    height: auto;
    min-height: 100px;
    background-color: #198754; /* 広い時は緑色に */
  }
  
  .step2-body {
    flex: 1;
    display: flex;
    flex-direction: column;
    justify-content: center;
  }
  
  /* テキストの切り替え */
  .is-narrow {
    display: none;
  }
  .is-wide {
    display: block;
  }
}

/* =コード解説エリア= */
.cq-step2-code-area {
  background-color: #282c34;
  color: #abb2bf;
  padding: 20px;
  border-radius: 6px;
  font-family: monospace;
  font-size: 13px;
  line-height: 1.6;
  border-left: 4px solid #0d6efd;
  overflow-x: auto;
  text-align: left;
}

名前付きコンテナによる詳細な制御

実務のレイアウトでは、「メインエリア」という大枠のコンテナの中に「カードリスト」という中枠のコンテナがあり、その中に個別のカードがある……といったように、コンテナが何重にも入れ子になる状態が当たり前に発生します。

デフォルトでは、@containerは「一番近くにある親コンテナ」のサイズを参照します。

しかし、「中のカードは、一番外側にある『メインエリア』の幅を基準にして変化させたい!」という時に必須になるのがcontainer-nameというプロパティです。

これを使うことで、コンテナに名前をつけ、指定した要素でサイズを参照できるようになります。

ちなみに、container-typecontainer-nameを同時に指定できるショートハンド(一括指定)としてcontainerプロパティがあります。

一括指定したい場合は、間にスラッシュ(/)を入れてcontainer: my-container / inline-size;と書くのが文法ルールです。(名前が先、スラッシュ、タイプが後)

ネストされたコンテナを管理するには、「実務では『container: 名前 / inline-size;』のショートハンドを使い、@containerを書く時は『@container 名前 (条件)』と、どのコンテナを参照しているのかを明示すること」です。

これにより、複雑なレイアウトでも意図しないバグを防げます。

⭕️ コンテナに名前をつければ、遠く離れた親のサイズも監視できる!

📦 大枠コンテナ(main-area)※ドラッグ可

📦 中枠コンテナ(sub-area)※ドラッグ可

私は中枠(青)の中にいますが、名前指定により大枠(緑)の幅だけを監視しています。
緑枠が500pxを超えると、オレンジ色に光ります!

/* ⭕️ コンテナに名前をつけ、ショートハンドで美しく定義する */
.outer-wrapper {
  /* 💡 名前 / タイプ の順で指定! */
  container: main-area / inline-size;
}

/* ⭕️ クエリを書く時は、名前を指名買いする! */
@container main-area (min-width: 500px) {
  .target-box {
    background-color: orange; /* 💡 「main-area」が500pxを超えた時だけ発動 */
  }
}
HTMLコード表示
<div class="cq-name-wrapper">
  
  <p class="cq-name-caption">⭕️ コンテナに名前をつければ、遠く離れた親のサイズも監視できる!</p>

  <div class="cq-name-demo-area">
    
    <!-- 💡 1. 大枠のコンテナ(緑色 / 名前:main-area) -->
    <div class="name-outer-container">
      <p class="name-label-outer">📦 大枠コンテナ(main-area)※ドラッグ可</p>
      
      <!-- 💡 2. 中枠のコンテナ(青色 / 名前:sub-area) -->
      <div class="name-inner-container">
        <p class="name-label-inner">📦 中枠コンテナ(sub-area)※ドラッグ可</p>
        
        <!-- 💡 3. 変化する要素 -->
        <div class="name-target-box">
          <p class="target-desc">
            私は中枠(青)の中にいますが、名前指定により<strong>大枠(緑)の幅だけ</strong>を監視しています。<br>
            緑枠が500pxを超えると、オレンジ色に光ります!
          </p>
        </div>
        
      </div>
      
    </div>

  </div>

  <div class="cq-name-code-area">
    <span class="hl-comment">/* ⭕️ コンテナに名前をつけ、ショートハンドで美しく定義する */</span><br>
    <span class="hl-blue">.outer-wrapper</span> {<br>
      <span class="hl-comment">/* 💡 名前 / タイプ の順で指定! */</span><br>
      <span class="hl-green">container:</span> <span class="hl-red">main-area / inline-size;</span><br>
    }<br><br>

    <span class="hl-comment">/* ⭕️ クエリを書く時は、名前を指名買いする! */</span><br>
    <span class="hl-blue">@container main-area (min-width: 500px)</span> {<br>
      <span class="hl-blue">.target-box</span> {<br>
        <span class="hl-green">background-color:</span> <span class="hl-red">orange;</span> <span class="hl-comment">/* 💡 「main-area」が500pxを超えた時だけ発動 */</span><br>
      }<br>
    }
  </div>

</div>
CSSコード表示
.cq-name-wrapper {
  background-color: #f8f9fa;
  padding: 30px;
  border-radius: 8px;
  border: 1px solid #dee2e6;
}

.cq-name-caption {
  font-size: 14px;
  font-weight: bold;
  margin-bottom: 20px;
  color: #198754;
  text-align: center;
}

.cq-name-demo-area {
  background-color: #e9ecef;
  padding: 30px 20px;
  border-radius: 8px;
  border: 1px dashed #adb5bd;
  margin-bottom: 20px;
}

/* === 💡 1. 大枠コンテナ(名前:main-area) === */
.name-outer-container {
  /* 👇 名前付きコンテナの定義(ショートハンド) 👇 */
  container: main-area / inline-size;
  
  background-color: #d1e7dd;
  border: 4px solid #198754;
  padding: 20px;
  border-radius: 8px;
  resize: horizontal;
  overflow: hidden;
  max-width: 100%;
  width: 350px; /* 初期状態 */
  margin: 0 auto;
  position: relative;
}

.name-outer-container::after {
  content: "↔ 緑枠をドラッグ";
  position: absolute;
  top: 5px;
  right: 15px;
  font-size: 11px;
  color: #198754;
  font-weight: bold;
}

.name-label-outer {
  margin-top: 0;
  margin-bottom: 15px;
  font-size: 14px;
  font-weight: bold;
  color: #198754;
}

/* === 💡 2. 中枠コンテナ(名前:sub-area) === */
.name-inner-container {
  /* 👇 中枠にも別の名前でコンテナを定義 👇 */
  container: sub-area / inline-size;
  
  background-color: #fff;
  border: 3px dashed #0d6efd;
  padding: 20px;
  border-radius: 8px;
  resize: horizontal;
  overflow: hidden;
  max-width: 100%;
  min-width: 200px;
  position: relative;
}

.name-inner-container::after {
  content: "↔ 青枠をドラッグ";
  position: absolute;
  top: 5px;
  right: 15px;
  font-size: 11px;
  color: #0d6efd;
  font-weight: bold;
}

.name-label-inner {
  margin-top: 0;
  margin-bottom: 15px;
  font-size: 13px;
  font-weight: bold;
  color: #0d6efd;
}

/* === 💡 3. 変化する要素(ターゲット)の初期状態 === */
.name-target-box {
  background-color: #6c757d; /* 初期はグレー */
  color: #fff;
  padding: 15px;
  border-radius: 6px;
  transition: all 0.3s ease;
}

.target-desc {
  margin: 0;
  font-size: 12px;
  line-height: 1.6;
}

/* === 💡 4. 名前付きコンテナクエリの指定 === */
/* 大枠(main-area)が 500px 以上になったら発動する! */
/* (※中枠の青い箱のサイズは一切関係ありません) */
@container main-area (min-width: 500px) {
  .name-target-box {
    background-color: #fd7e14; /* オレンジ色に変化! */
    box-shadow: 0 0 15px rgba(253, 126, 20, 0.6);
    transform: scale(1.02);
  }
}

/* =コード解説エリア= */
.cq-name-code-area {
  background-color: #282c34;
  color: #abb2bf;
  padding: 20px;
  border-radius: 6px;
  font-family: monospace;
  font-size: 13px;
  line-height: 1.6;
  border-left: 4px solid #0d6efd;
  overflow-x: auto;
  text-align: left;
}

コンテナクエリを使ったレスポンシブUI実装

実際のWeb制作の現場でコンテナクエリがどのように活用されているのかを見ていきましょう。

コンテナクエリが役立つのは、ブログの記事カードやECサイトの商品パネルなど、サイト内の様々な場所で使い回されるコンポーネントを作成する時です。

ここでは、実務で頻出する実践的なUI実装パターンとスタイル管理手法について解説します。

コンテナクエリを使ったレスポンシブUI実装
  • サイドバーとメインエリアでレイアウトが変わるカードUI作成
  • CSS変数(カスタムプロパティ)を組み合わせたスタイル管理

サイドバーとメインエリアでレイアウトが変わるカードUI作成

Webサイトのレイアウトでは、画面の横幅を広く使うメインエリアと狭い幅に情報を詰め込むサイドバーが存在します。

従来のメディアクエリでは、同じ記事カードを両方に配置しようとすると、クラス名を分けて別々のCSSを書く必要がありました。

しかし、コンテナクエリを使えば「たった一つのHTMLとCSS」で、配置された場所の広さを自ら察知してレイアウトを変えるカードUIを作ることができます。

汎用的なコンポーネントを設計する際は、「カード部品を作る側(CSS)は『外側のことは一切気にせず、自分の直近の幅だけで完結させる』ことです。

そして、ページを組み上げる側(HTML)は『カードを配置する可能性のある全てのエリア(ラッパー)にcontainer-typeを指定する』こと」です。

⭕️ 同じHTMLコードのまま、メインエリアでは横並び、サイドでは縦並びに!

📝メインエリア
サムネイル画像
CSS
コンテナクエリの実践テクニック

親の要素の幅に合わせて、画像とテキストが横並びに展開されています。広いスペースを有効活用するレイアウトです。

サムネイル画像
HTML
レスポンシブなマークアップ術

こちらもメインエリアに置かれているため、自動的に横並びの広々としたレイアウトが適用されています。

📌サイドバー
サムネイル画像
Design
UIデザインの基本と原則

サイドバーの狭い箱に入ったため、縦並びに切り替わりました!

/* ⭕️ 配置するエリアは全てコンテナ化しておく */
.prac-main-area, .prac-sidebar-area {
  container-type: inline-size; /* 💡 これでカードが自身の幅を認識できる */
}

/* ⭕️ 記事カードは、置かれた場所の幅に合わせて勝手に変形する */
@container (min-width: 480px) {
  .prac-article-card {
    display: flex;
    flex-direction: row; /* 💡 幅が480px以上の広い箱の中だけで横並びになる */
    align-items: center;
  }
}
HTMLコード表示
<div class="prac-card-wrapper">
  
  <p class="prac-card-caption">⭕️ 同じHTMLコードのまま、メインエリアでは横並び、サイドでは縦並びに!</p>

  <!-- ページ全体のレイアウト枠 -->
  <div class="prac-layout-grid">
    
    <!-- 💡 1. メインエリア(広い) -->
    <div class="prac-main-area">
      <div class="prac-area-title">📝メインエリア</div>
      
      <!-- ★ 全く同じ記事カード部品 -->
      <article class="prac-article-card">
        <div class="prac-card-thumb">サムネイル画像</div>
        <div class="prac-card-content">
          <span class="prac-card-tag">CSS</span>
          <div class="prac-card-title">コンテナクエリの実践テクニック</div>
          <p class="prac-card-excerpt">
            親の要素の幅に合わせて、画像とテキストが横並びに展開されています。広いスペースを有効活用するレイアウトです。
          </p>
        </div>
      </article>

      <article class="prac-article-card">
        <div class="prac-card-thumb">サムネイル画像</div>
        <div class="prac-card-content">
          <span class="prac-card-tag">HTML</span>
          <div class="prac-card-title">レスポンシブなマークアップ術</div>
          <p class="prac-card-excerpt">
            こちらもメインエリアに置かれているため、自動的に横並びの広々としたレイアウトが適用されています。
          </p>
        </div>
      </article>

    </div>

    <!-- 💡 2. サイドバーエリア(狭い) -->
    <div class="prac-sidebar-area">
      <div class="prac-area-title">📌サイドバー</div>
      
      <!-- ★ 全く同じ記事カード部品 -->
      <article class="prac-article-card">
        <div class="prac-card-thumb">サムネイル画像</div>
        <div class="prac-card-content">
          <span class="prac-card-tag">Design</span>
          <div class="prac-card-title">UIデザインの基本と原則</div>
          <p class="prac-card-excerpt">
            サイドバーの狭い箱に入ったため、縦並びに切り替わりました!
          </p>
        </div>
      </article>

    </div>

  </div>

  <div class="prac-card-code-area">
    <span class="hl-comment">/* ⭕️ 配置するエリアは全てコンテナ化しておく */</span><br>
    <span class="hl-blue">.prac-main-area, .prac-sidebar-area</span> {<br>
      <span class="hl-green">container-type:</span> <span class="hl-red">inline-size;</span> <span class="hl-comment">/* 💡 これでカードが自身の幅を認識できる */</span><br>
    }<br><br>

    <span class="hl-comment">/* ⭕️ 記事カードは、置かれた場所の幅に合わせて勝手に変形する */</span><br>
    <span class="hl-blue">@container (min-width: 480px)</span> {<br>
      <span class="hl-blue">.prac-article-card</span> {<br>
        <span class="hl-green">display:</span> <span class="hl-red">flex;</span><br>
        <span class="hl-green">flex-direction:</span> <span class="hl-red">row;</span> <span class="hl-comment">/* 💡 幅が480px以上の広い箱の中だけで横並びになる */</span><br>
        <span class="hl-green">align-items:</span> <span class="hl-red">center;</span><br>
      }<br>
    }
  </div>

</div>
CSSコード表示
.prac-card-wrapper {
  background-color: #f8f9fa;
  padding: 30px;
  border-radius: 8px;
  border: 1px solid #dee2e6;
}

.prac-card-caption {
  font-size: 14px;
  font-weight: bold;
  margin-bottom: 20px;
  color: #198754;
  text-align: center;
}

/* ページ全体のグリッドレイアウト */
.prac-layout-grid {
  display: grid;
  gap: 20px;
  /* メイン(広) と サイド(狭) の比率 */
  grid-template-columns: 2fr 1fr; 
  margin-bottom: 20px;
}

/* スマホサイズでは縦に積む */
@media (max-width: 768px) {
  .prac-layout-grid {
    grid-template-columns: 1fr;
  }
}

.prac-area-title {
  font-size: 16px;
  margin-top: 0;
  margin-bottom: 15px;
  color: #333;
  border-bottom: 2px solid #adb5bd;
  padding-bottom: 8px;
}

/* === 💡 1. 各エリアのコンテナ定義 === */
.prac-main-area {
  background-color: #e9ecef;
  padding: 20px;
  border-radius: 8px;
  /* メインエリアをコンテナ化 */
  container-type: inline-size;
}

.prac-sidebar-area {
  background-color: #e9ecef;
  padding: 20px;
  border-radius: 8px;
  /* サイドバーエリアをコンテナ化 */
  container-type: inline-size;
}

/* === 💡 2. 記事カードのベーススタイル(狭い時用) === */
.prac-article-card {
  background-color: #fff;
  border-radius: 8px;
  border: 1px solid #ced4da;
  overflow: hidden;
  margin-bottom: 15px;
  /* ベースは縦並び */
  display: flex;
  flex-direction: column;
}

.prac-article-card:last-child {
  margin-bottom: 0;
}

.prac-card-thumb {
  background-color: #6c757d;
  color: #fff;
  display: flex;
  align-items: center;
  justify-content: center;
  font-weight: bold;
  font-size: 14px;
  width: 100%;
  /* 縦並びの時の画像の高さ */
  height: 140px; 
}

.prac-card-content {
  padding: 15px;
}

.prac-card-tag {
  display: inline-block;
  background-color: #0d6efd;
  color: #fff;
  font-size: 11px;
  font-weight: bold;
  padding: 3px 8px;
  border-radius: 4px;
  margin-bottom: 8px;
}

.prac-card-title {
  margin-top: 0;
  margin-bottom: 8px;
  font-size: 16px;
  color: #212529;
  line-height: 1.4;
}

.prac-card-excerpt {
  margin: 0;
  font-size: 13px;
  color: #6c757d;
  line-height: 1.5;
}

/* === 💡 3. コンテナクエリの指定(広い時用) === */
/* 箱の幅が 480px 以上になったら横並びに変形! */
@container (min-width: 480px) {
  
  .prac-article-card {
    /* 横並びに切り替え */
    flex-direction: row;
    align-items: stretch;
  }
  
  .prac-card-thumb {
    /* 画像を左側に固定幅で配置 */
    width: 200px;
    height: auto;
    min-height: 100%;
  }
  
  .prac-card-content {
    /* テキストエリアが残りの幅を埋める */
    flex: 1;
    display: flex;
    flex-direction: column;
    justify-content: center;
  }
}

/* =コード解説エリア= */
.prac-card-code-area {
  background-color: #282c34;
  color: #abb2bf;
  padding: 20px;
  border-radius: 6px;
  font-family: monospace;
  font-size: 13px;
  line-height: 1.6;
  border-left: 4px solid #0d6efd;
  overflow-x: auto;
  text-align: left;
}

CSS変数(カスタムプロパティ)を組み合わせたスタイル管理

現代のCSS設計において、CSS変数(カスタムプロパティ)の組み合わせは役立ちます。

箱のサイズが変わった時、レイアウトだけでなく「余白の広さ」「フォントサイズ」「テーマカラー」なども一気に切り替えたい場合があります。

まともに書くと、CSSのコード量が膨れ上がってしまいますが、CSS変数を組み合わせることでスマートに管理できます。

スタイルを管理するには、「コンポーネントの根元(ルートクラス)でデザインの数値を『CSS変数』として定義し@containerの中では『変数の値だけを上書き』すること」です。

これにより、たった数行の変更でコンポーネント全体の見栄えを切り替えることができます。

⭕️ 箱を広げてみよう!CSS変数を使えば、デザインが一瞬で切り替わる!

CSS変数 × コンテナクエリ

箱が狭い時は「余白が小さく、文字も小さく、テーマ色は青」。
箱が広くなると「余白が広く、文字も大きく、テーマ色は紫」に変化します!

/* ⭕️ コンポーネントのベースとなる数値を「変数」で定義する */
.var-card {
  –card-padding: 15px; /* ベースの余白 */
  –card-theme-color: #0d6efd; /* ベースの色(青) */
  –card-title-size: 16px; /* ベースの文字サイズ */
}

/* ⭕️ コンテナクエリ内では「変数を上書き」するだけ! */
@container (min-width: 500px) {
  .var-card {
    –card-padding: 30px; /* 💡 余白を広く! */
    –card-theme-color: #6f42c1; /* 💡 色を紫に! */
    –card-title-size: 24px; /* 💡 文字を大きく! */
  }
}
HTMLコード表示
<div class="prac-var-wrapper">
  
  <p class="prac-var-caption">⭕️ 箱を広げてみよう!CSS変数を使えば、デザインが一瞬で切り替わる!</p>

  <div class="prac-var-demo-area">
    
    <!-- 💡 基準となる親コンテナ -->
    <div class="var-container-box">
      
      <!-- ★ 変数で管理されたコンポーネント -->
      <div class="var-card">
        <div class="var-card-header">
          <div class="var-card-title">CSS変数 × コンテナクエリ</div>
        </div>
        <div class="var-card-body">
          <p class="var-card-text">
            箱が狭い時は「余白が小さく、文字も小さく、テーマ色は青」。<br>
            箱が広くなると「余白が広く、文字も大きく、テーマ色は紫」に変化します!
          </p>
          <button class="var-card-btn">詳細を見る</button>
        </div>
      </div>
      
    </div>

  </div>

  <div class="prac-var-code-area">
    <span class="hl-comment">/* ⭕️ コンポーネントのベースとなる数値を「変数」で定義する */</span><br>
    <span class="hl-blue">.var-card</span> {<br>
      <span class="hl-green">--card-padding:</span> <span class="hl-red">15px;</span> <span class="hl-comment">/* ベースの余白 */</span><br>
      <span class="hl-green">--card-theme-color:</span> <span class="hl-red">#0d6efd;</span> <span class="hl-comment">/* ベースの色(青) */</span><br>
      <span class="hl-green">--card-title-size:</span> <span class="hl-red">16px;</span> <span class="hl-comment">/* ベースの文字サイズ */</span><br>
    }<br><br>

    <span class="hl-comment">/* ⭕️ コンテナクエリ内では「変数を上書き」するだけ! */</span><br>
    <span class="hl-blue">@container (min-width: 500px)</span> {<br>
      <span class="hl-blue">.var-card</span> {<br>
        <span class="hl-green">--card-padding:</span> <span class="hl-red">30px;</span> <span class="hl-comment">/* 💡 余白を広く! */</span><br>
        <span class="hl-green">--card-theme-color:</span> <span class="hl-red">#6f42c1;</span> <span class="hl-comment">/* 💡 色を紫に! */</span><br>
        <span class="hl-green">--card-title-size:</span> <span class="hl-red">24px;</span> <span class="hl-comment">/* 💡 文字を大きく! */</span><br>
      }<br>
    }
  </div>

</div>
CSSコード表示
.prac-var-wrapper {
  background-color: #f8f9fa;
  padding: 30px;
  border-radius: 8px;
  border: 1px solid #dee2e6;
}

.prac-var-caption {
  font-size: 14px;
  font-weight: bold;
  margin-bottom: 20px;
  color: #198754;
  text-align: center;
}

.prac-var-demo-area {
  background-color: #e9ecef;
  padding: 30px 20px;
  border-radius: 8px;
  border: 1px dashed #adb5bd;
  margin-bottom: 20px;
}

/* === 💡 1. コンテナの定義 === */
.var-container-box {
  /* コンテナ化 */
  container-type: inline-size;
  
  background-color: #fff;
  border: 4px dashed #adb5bd;
  padding: 20px;
  border-radius: 8px;
  margin: 0 auto;
  position: relative;
  
  /* ドラッグして幅を変えられるようにする */
  resize: horizontal;
  overflow: hidden;
  max-width: 100%;
  min-width: 250px;
  width: 320px; /* 初期状態(狭い) */
}

.var-container-box::after {
  content: "↔ 箱を広げる";
  position: absolute;
  bottom: 0;
  right: 15px;
  font-size: 11px;
  color: #6c757d;
  font-weight: bold;
  pointer-events: none;
}

/* === 💡 2. CSS変数を使ったコンポーネント設計 === */
.var-card {
  /* 👇 ここでコンポーネント全体で使う「変数(デザインのルール)」を定義 👇 */
  --card-padding: 15px;
  --card-theme-color: #0d6efd; /* 初期テーマは青 */
  --card-title-size: 16px;
  --card-text-size: 13px;
  
  background-color: #f8f9fa;
  border: 2px solid var(--card-theme-color); /* 変数を使用 */
  border-radius: 8px;
  overflow: hidden;
  /* スムーズに変化させるためのアニメーション設定 */
  transition: all 0.4s ease;
}

/* ヘッダー部分 */
.var-card-header {
  background-color: var(--card-theme-color); /* 変数を使用 */
  padding: var(--card-padding); /* 変数を使用 */
  transition: all 0.4s ease;
}

.var-card-title {
  margin: 0;
  color: #fff;
  font-weight: bold;
  font-size: var(--card-title-size); /* 変数を使用 */
  transition: font-size 0.4s ease;
}

/* ボディ部分 */
.var-card-body {
  padding: var(--card-padding); /* 変数を使用 */
  transition: padding 0.4s ease;
}

.var-card-text {
  margin-top: 0;
  margin-bottom: 20px;
  color: #333;
  line-height: 1.6;
  font-size: var(--card-text-size); /* 変数を使用 */
  transition: font-size 0.4s ease;
}

/* ボタン部分 */
.var-card-btn {
  display: inline-block;
  background-color: transparent;
  color: var(--card-theme-color); /* 変数を使用 */
  border: 2px solid var(--card-theme-color); /* 変数を使用 */
  padding: 8px 16px;
  border-radius: 30px;
  font-weight: bold;
  font-size: var(--card-text-size);
  cursor: pointer;
  transition: all 0.4s ease;
}

.var-card-btn:hover {
  background-color: var(--card-theme-color);
  color: #fff;
}

/* === 💡 3. コンテナクエリで「変数の値だけ」を上書きする === */
/* 箱が500px以上になったら発動 */
@container (min-width: 500px) {
  .var-card {
    /* 👇 デザインのルール(変数)だけを丸ごと書き換える! 👇 */
    --card-padding: 30px;          /* 余白を広く */
    --card-theme-color: #6f42c1;   /* テーマ色を紫に */
    --card-title-size: 24px;       /* タイトルを大きく */
    --card-text-size: 15px;        /* 本文も少し大きく */
    
    /* ※要素ごとの細かいCSSを再定義する必要は一切ありません! */
  }
}

/* =コード解説エリア= */
.prac-var-code-area {
  background-color: #282c34;
  color: #abb2bf;
  padding: 20px;
  border-radius: 6px;
  font-family: monospace;
  font-size: 13px;
  line-height: 1.6;
  border-left: 4px solid #0d6efd;
  overflow-x: auto;
  text-align: left;
}

コンテナクエリの対応ブラウザと注意点

コンテナクエリは、これまでのWebデザインの常識を覆す機能です。

しかし、「どんなブラウザでも無条件に使えるのか?」「従来の単位(%やvw)とどう違うのか?」といった疑問や注意点が浮かび上がってきます。

実務でコンテナクエリを導入するために知っておくべきブラウザの対応状況と新しく追加された「コンテナ単位」の活用方法について解説します。

コンテナクエリの対応ブラウザと注意点
  • ブラウザサポート状況とポリフィル
  • cqw/cqhなどのコンテナクエリ単位の使い方

ブラウザサポート状況とポリフィル

「新機能を使いたいけど、ブラウザ対応が心配…」というのはWeb制作者の悩みです。

結論から言うと、コンテナクエリは主要なモダンブラウザ(Chrome、Edge、Safari、Firefox)の最新バージョンで完全にサポートされています(Can I Use参照)。

そのため、一般的なプロジェクトであれば今すぐ実務に投入して問題ありません。

しかし、古い端末やアップデートされていないブラウザへの配慮が必要な案件では注意が必要です。

実務で導入するには、「@supportsを使って『コンテナクエリ対応ブラウザ』と『非対応ブラウザ(従来のメディアクエリで対応)』を分岐させるか、Googleが提供している公式の『Polyfill(ポリフィル:未対応ブラウザでも動かすためのJavaScript)』を読み込ませておくこと」です。

⭕️ 古いブラウザで崩壊させない!@supports で安全網(フォールバック)を張れ!

ブラウザ対応チェック

⚠️ 警告:あなたのブラウザはコンテナクエリに未対応(または非対応のフリ)です。安全のため、従来の縦並びレイアウトを維持しています。

✅ 成功:あなたのブラウザはコンテナクエリに対応しています!そのため、広い箱の中で美しく横並びに展開されています。

/* ⭕️ まず全員(非対応ブラウザ)が安全に見えるベースを作る */
.support-card {
  display: flex;
  flex-direction: column; /* 💡 非対応環境でも絶対に崩れない「縦並び」をベースにする */
}

/* ⭕️ @supports で「コンテナクエリが使えるか?」を判定する */
@supports (container-type: inline-size) {

  @container (min-width: 400px) {
    .support-card {
      flex-direction: row; /* 💡 対応ブラウザのみ、この高度なレイアウト(横並び)が発動! */
    }
  }
}
HTMLコード表示
<div class="cq-support-wrapper">
  
  <p class="cq-support-caption">⭕️ 古いブラウザで崩壊させない!@supports で安全網(フォールバック)を張れ!</p>

  <div class="cq-support-demo-area">
    
    <div class="support-container">
      
      <!-- ブラウザの対応状況によって表示が変わるカード -->
      <div class="support-card">
        <div class="support-icon"></div>
        <div class="support-body">
          <div class="support-title">ブラウザ対応チェック</div>
          <p class="support-fallback-msg">
            ⚠️ 警告:あなたのブラウザはコンテナクエリに未対応(または非対応のフリ)です。安全のため、従来の縦並びレイアウトを維持しています。
          </p>
          <p class="support-success-msg">
            ✅ 成功:あなたのブラウザはコンテナクエリに対応しています!そのため、広い箱の中で美しく横並びに展開されています。
          </p>
        </div>
      </div>
      
    </div>

  </div>

  <div class="cq-support-code-area">
    <span class="hl-comment">/* ⭕️ まず全員(非対応ブラウザ)が安全に見えるベースを作る */</span><br>
    <span class="hl-blue">.support-card</span> {<br>
      <span class="hl-green">display:</span> <span class="hl-red">flex;</span><br>
      <span class="hl-green">flex-direction:</span> <span class="hl-red">column;</span> <span class="hl-comment">/* 💡 非対応環境でも絶対に崩れない「縦並び」をベースにする */</span><br>
    }<br><br>

    <span class="hl-comment">/* ⭕️ @supports で「コンテナクエリが使えるか?」を判定する */</span><br>
    <span class="hl-blue">@supports (container-type: inline-size)</span> {<br>
    <br>
      <span class="hl-blue">@container (min-width: 400px)</span> {<br>
        <span class="hl-blue">.support-card</span> {<br>
          <span class="hl-green">flex-direction:</span> <span class="hl-red">row;</span> <span class="hl-comment">/* 💡 対応ブラウザのみ、この高度なレイアウト(横並び)が発動! */</span><br>
        }<br>
      }<br>
    }
  </div>

</div>
CSSコード表示
.cq-support-wrapper {
  background-color: #f8f9fa;
  padding: 30px;
  border-radius: 8px;
  border: 1px solid #dee2e6;
}

.cq-support-caption {
  font-size: 14px;
  font-weight: bold;
  margin-bottom: 20px;
  color: #198754;
  text-align: center;
}

.cq-support-demo-area {
  background-color: #e9ecef;
  padding: 30px 20px;
  border-radius: 8px;
  border: 1px dashed #adb5bd;
  margin-bottom: 20px;
}

/* === 💡 1. コンテナの定義 === */
.support-container {
  container-type: inline-size;
  background-color: #fff;
  border: 4px dashed #adb5bd;
  padding: 20px;
  border-radius: 8px;
}

/* === 💡 2. 安全なベーススタイル(フォールバック用) === */
.support-card {
  background-color: #fff;
  border-radius: 8px;
  border: 2px solid #dc3545; /* 非対応時のテーマ色は赤 */
  overflow: hidden;
  /* ⚠️ 非対応ブラウザでも絶対に崩れない「縦並び」をベースにする */
  display: flex;
  flex-direction: column; 
}

.support-icon {
  background-color: #dc3545;
  color: #fff;
  height: 100px;
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 40px;
}
/* アイコンの中身(疑似要素で表現) */
.support-icon::after {
  content: "⚠️";
}

.support-body {
  padding: 20px;
}

.support-title {
  margin-top: 0;
  margin-bottom: 10px;
  font-size: 18px;
  color: #dc3545;
}

/* メッセージの表示制御 */
.support-fallback-msg {
  display: block; /* 初期表示 */
  margin: 0;
  font-size: 14px;
  line-height: 1.6;
  color: #333;
}

.support-success-msg {
  display: none; /* 初期は隠す */
  margin: 0;
  font-size: 14px;
  line-height: 1.6;
  color: #333;
}

/* === 💡 3. 対応ブラウザかどうかの判定とスタイル適用 === */
/* ブラウザが container-type をサポートしているか判定! */
@supports (container-type: inline-size) {
  
  /* 対応している場合のみ、コンテナクエリが有効になる */
  @container (min-width: 400px) {
    
    .support-card {
      flex-direction: row; /* 横並びに昇格! */
      border-color: #198754; /* 成功の緑色に */
    }
    
    .support-icon {
      background-color: #198754;
      width: 120px;
      height: auto;
      min-height: 100%;
    }
    .support-icon::after {
      content: "✅";
    }
    
    .support-title {
      color: #198754;
    }
    
    /* メッセージを切り替える */
    .support-fallback-msg {
      display: none;
    }
    .support-success-msg {
      display: block;
    }
  }
}

/* =コード解説エリア= */
.cq-support-code-area {
  background-color: #282c34;
  color: #abb2bf;
  padding: 20px;
  border-radius: 6px;
  font-family: monospace;
  font-size: 13px;
  line-height: 1.6;
  border-left: 4px solid #0d6efd;
  overflow-x: auto;
  text-align: left;
}

cqw/cqhなどのコンテナクエリ単位の使い方

コンテナクエリの登場に合わせて、新しい「単位」も追加されました。

従来、画面幅に合わせて文字をスムーズに拡大縮小させたい時はvw(ビューポート幅=画面全体の幅の1%)を使っていました。

しかし、コンテナ(親要素)の幅の1%を意味するcqw (Container Query Width) を使うことができます。

  • cqw:コンテナの幅の 1%
  • cqh:コンテナの高さの 1%
  • cqi:コンテナのインライン方向(通常は幅)の 1%
  • cqmin:cqwcqhのうち、小さい方の 1%

単位を使いこなすには、「cqwなどの単位を使う際は、その要素を包む親にcontainer-typeが指定されているか確認すること」です。

そして、「文字が小さくなりすぎたり大きくなりすぎたりするのを防ぐため、clamp(14px, 5cqw, 24px)のようにclamp()関数と組み合わせて安全な最小・最大サイズを保証すること」です。

⭕️ 箱を伸縮させてみよう!箱の幅(cqw)に合わせて文字が滑らかに大きくなる!

流体タイポグラフィ

このテキストのサイズと、周りの余白は cqw(コンテナの幅の1%)で指定されています。
そのため、ブラウザの画面幅を変えなくても、この「点線の箱」が伸縮するだけで、中身がまるで水のように滑らかにサイズを変えます!

/* ❌ 罠:親がコンテナ化されていないと、cqw は一切機能しない! */
.unit-container {
  container-type: inline-size; /* 💡 この1行があるから cqw が計算できる! */
}

/* ⭕️ cqw は clamp() で囲んで「小さすぎ・大きすぎ」を防ぐ! */
.unit-title {
  /* 💡 最小18px 〜 コンテナ幅の6% 〜 最大36px の間で無段階に変化する! */
  font-size: clamp(18px, 6cqw, 36px);
}

.unit-card {
  /* 💡 余白(padding)もコンテナの幅に連動して広くなる! */
  padding: clamp(15px, 5cqw, 40px);
}
HTMLコード表示
<div class="cq-unit-wrapper">
  
  <p class="cq-unit-caption">⭕️ 箱を伸縮させてみよう!箱の幅(cqw)に合わせて文字が滑らかに大きくなる!</p>

  <div class="cq-unit-demo-area">
    
    <!-- 💡 コンテナ(基準となる親要素) -->
    <div class="unit-container">
      
      <!-- 変化する中身 -->
      <div class="unit-card">
        <div class="unit-title">流体タイポグラフィ</div>
        <p class="unit-text">
          このテキストのサイズと、周りの余白は <code>cqw</code>(コンテナの幅の1%)で指定されています。<br>
          そのため、ブラウザの画面幅を変えなくても、この「点線の箱」が伸縮するだけで、中身がまるで水のように滑らかにサイズを変えます!
        </p>
      </div>

    </div>

  </div>

  <div class="cq-unit-code-area">
    <span class="hl-comment">/* ❌ 罠:親がコンテナ化されていないと、cqw は一切機能しない! */</span><br>
    <span class="hl-blue">.unit-container</span> {<br>
      <span class="hl-green">container-type:</span> <span class="hl-red">inline-size;</span> <span class="hl-comment">/* 💡 この1行があるから cqw が計算できる! */</span><br>
    }<br><br>

    <span class="hl-comment">/* ⭕️ cqw は clamp() で囲んで「小さすぎ・大きすぎ」を防ぐ! */</span><br>
    <span class="hl-blue">.unit-title</span> {<br>
      <span class="hl-comment">/* 💡 最小18px 〜 コンテナ幅の6% 〜 最大36px の間で無段階に変化する! */</span><br>
      <span class="hl-green">font-size:</span> <span class="hl-red">clamp(18px, 6cqw, 36px);</span><br>
    }<br>
    <br>
    <span class="hl-blue">.unit-card</span> {<br>
      <span class="hl-comment">/* 💡 余白(padding)もコンテナの幅に連動して広くなる! */</span><br>
      <span class="hl-green">padding:</span> <span class="hl-red">clamp(15px, 5cqw, 40px);</span><br>
    }
  </div>

</div>
CSSコード表示
.cq-unit-wrapper {
  background-color: #f8f9fa;
  padding: 30px;
  border-radius: 8px;
  border: 1px solid #dee2e6;
}

.cq-unit-caption {
  font-size: 14px;
  font-weight: bold;
  margin-bottom: 20px;
  color: #198754;
  text-align: center;
}

.cq-unit-demo-area {
  background-color: #e9ecef;
  padding: 30px 20px;
  border-radius: 8px;
  border: 1px dashed #adb5bd;
  margin-bottom: 20px;
}

/* === 💡 1. コンテナの定義 === */
.unit-container {
  /* 👇 これがないと中の cqw が機能しない! 👇 */
  container-type: inline-size;
  
  background-color: #fff;
  border: 4px dashed #0d6efd;
  padding: 20px;
  border-radius: 8px;
  margin: 0 auto;
  position: relative;
  
  /* ドラッグして幅を変えられるようにする */
  resize: horizontal;
  overflow: hidden;
  max-width: 100%;
  min-width: 250px;
  width: 300px; /* 初期状態(狭い) */
}

.unit-container::after {
  content: "↔ 箱を伸縮させる";
  position: absolute;
  bottom: 0;
  right: 15px;
  font-size: 11px;
  color: #0d6efd;
  font-weight: bold;
  pointer-events: none;
}

/* === 💡 2. 新単位 cqw を使ったスタイリング === */
.unit-card {
  background-color: #0d6efd;
  color: #fff;
  border-radius: 8px;
  
  /* 💡 余白を箱の幅に連動させる(最小15px 〜 5cqw 〜 最大40px) */
  padding: clamp(15px, 5cqw, 40px);
}

.unit-title {
  margin-top: 0;
  margin-bottom: 10px;
  font-weight: bold;
  
  /* 💡 見出しの文字サイズを箱の幅に連動させる(最小18px 〜 6cqw 〜 最大36px) */
  font-size: clamp(18px, 6cqw, 36px);
  
  /* 変化を分かりやすくするための下線 */
  border-bottom: 2px solid rgba(255,255,255,0.3);
  padding-bottom: 10px;
  line-height: 1.3;
}

.unit-text {
  margin: 0;
  line-height: 1.6;
  
  /* 💡 本文の文字サイズも箱の幅に連動させる(最小13px 〜 3.5cqw 〜 最大20px) */
  font-size: clamp(13px, 3.5cqw, 20px);
}

.unit-text code {
  background-color: rgba(0,0,0,0.2);
  padding: 2px 6px;
  border-radius: 4px;
}

/* =コード解説エリア= */
.cq-unit-code-area {
  background-color: #282c34;
  color: #abb2bf;
  padding: 20px;
  border-radius: 6px;
  font-family: monospace;
  font-size: 13px;
  line-height: 1.6;
  border-left: 4px solid #0d6efd;
  overflow-x: auto;
  text-align: left;
}

まとめ

分かりやすいようにまとめを記載します。

本記事のまとめ
  • 最大の特徴
    画面全体の幅ではなく「自身を包む親要素(箱)の幅」を基準にしてスタイルを切り替える。
  • 必須の事前準備
    コンテナクエリを発動させるには、基準となる親要素にcontainer-type: inline-size;を指定しなければならない。
  • スタイルの指定方法
    親要素を定義した後、子要素に対する条件分岐を@container (min-width: 400px) { ... }のように記述する。
  • やってはいけないタブー
    @containerの中で「コンテナ自身のスタイル(背景色など)」を変更すると、無限ループやバグの原因となるため絶対に行わない。
  • 名前付きコンテナ
    container: main-area / inline-size;のように名前(main-area)をつけることで、深く入れ子になった要素から特定の親のサイズを指名買いで参照できる。
  • コンポーネント化との相性
    メインエリアやサイドバーなど「置かれた場所の広さ」を自ら判断してレイアウト(縦並び・横並び)を変えるため、汎用性の高いUI部品が作れる。
  • CSS変数との合わせ技
    @container内でCSS変数(--padding--theme-colorなど)の数値を上書きすることで、デザイン全体の切り替えを数行で管理できる。
  • ブラウザ対応と安全網
    最新の主要ブラウザでは利用可能だが、古い環境向けには@supportsを使ってコンテナクエリ対応ブラウザのみ高度なレイアウトを適用するフォールバック設計が必須である。
  • 単位「cqw」
    コンテナ幅の1%を意味するcqwを使えば、親の箱の伸縮に連動する「流体タイポグラフィ」が実現できる。
    clamp()関数と組み合わせて暴走を防ぐ。

よくある質問(FAQ)

メディアクエリとコンテナクエリの違いは何ですか?

基準となる「対象」が全く異なります。

メディアクエリは「画面全体(ブラウザの表示幅)」を基準にしてスタイルを切り替えますが、コンテナクエリは「要素を包んでいる親要素(箱の幅)」を基準にします。

これにより、同じカード部品でも、広いメインエリアに置かれた時は横並び、狭いサイドバーに置かれた時は縦並びといった自己判断ができるようになります。

@containerを書いても全く効かないのですが、なぜですか?

基準となる親要素に「コンテナとしての宣言」をしていないことが最も多い原因です。

コンテナクエリを発動させるには、レイアウトを変えたい要素を包んでいる親要素に対して、container-type: inline-size;を指定する必要があります。

これを忘れると、ブラウザはどの幅を参照していいか分からず、クエリを無視してしまいます。

実務案件でコンテナクエリを使っても問題ありませんか?

主要なモダンブラウザ(Chrome、Edge、Safari、Firefox)の最新版では既に完全にサポートされているため、基本的には実務で導入しても問題ありません。

ただし、iOS 15以前の古いiPhoneなど、アップデートされていない環境では表示が崩れる可能性があります。

そのため、万全を期す場合は@supports (container-type: inline-size)を用いて、非対応ブラウザ向けの代替レイアウトを併記しておくのがよいです。

単位のcqwやcqhとはどのような時に使うのですか?

親要素のサイズに合わせて、文字の大きさや余白を滑らかに伸縮させたい時に使います。

従来のvwは「画面幅の1%」でしたが、cqwは「コンテナ幅の1%」を意味します。

これをfont-size: clamp(16px, 5cqw, 24px);のように指定することで、箱の伸縮に連動する美しい流体タイポグラフィを実現できます。

コンテナクエリの登場で、従来のメディアクエリは不要になりますか?

いいえ、メディアクエリが不要になるわけではなく、役割が分担されるようになります。

ページ全体の大枠(ヘッダーの出し分けや、メインカラムとサイドバーの配置などマクロなレイアウト)には引き続きメディアクエリを使用されます。

その中に配置される個別のカードやボタンなど(ミクロなコンポーネント)にはコンテナクエリを使用する、という適材適所の使い分けが今後のモダンCSSのスタンダードになります。

CONTACT

サイト制作でお困りの人はお気軽にご連絡ください。
どんなお悩み事も丁寧に返信させて頂きます。

WordPress移行
Webサイトを公開しよう!

「どのサーバーを選べばいいか分からない…」そんな悩みを解決!
WordPressデビューに最適なサーバーを徹底比較しました。

この記事を書いた人

sugiのアバター sugi Site operator

【経歴】玉川大学工学部卒業→新卒SIer企業入社→2年半後に独立→プログラミングスクール運営/受託案件→フリーランスエンジニア&SEOコンサル→Python特化のコンテンツサイトJob Code&UIコピペサイトCode Stock運営中

目次