HOME / BLOG
BLOG

CSS container query の使い方【実践例付き】

デフォルト画像

レスポンシブ対応というと、まず@mediaを思い浮かべる人が多いはずです。ただ、media queryは画面幅を見てスタイルを切り替えるため、同じカードをメインカラム、サイドバー、一覧、関連記事など複数の場所で使い回すと、コンポーネント単位では扱いにくくなることがあります。

CSS Container Queryを使うと、画面幅ではなく親コンテナの幅を基準にスタイルを変えられます。この記事では、基本構文、実践例、よくある失敗、CodePenに貼って試せるデモまでまとめます。

Container Queryとは

Container Queryは、要素が置かれているコンテナのサイズや状態に応じて、子要素のスタイルを切り替えるCSSの仕組みです。MDNでも、media queryがviewportを基準にするのに対し、container queryはコンテナの属性を基準にできる代替手段として説明されています。

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

@container (min-width: 600px) {
  .card {
    display: grid;
    grid-template-columns: 240px 1fr;
  }
}

実務では、横幅だけを見るinline-sizeを使うことが多いです。左右書きの日本語・英語サイトでは、ほぼ「コンテナの横幅」と考えて問題ありません。

基本構文

まず、基準にしたい親要素へcontainer-typeを指定します。その子孫要素に対して@container内でスタイルを書きます。

.component-wrap {
  container-type: inline-size;
}

@container (width >= 480px) {
  .component {
    padding: 32px;
  }
}

名前を付けたい場合はcontainer-name、またはショートハンドのcontainerを使います。複数のコンテナが入れ子になるレイアウトでは、名前を付けると意図しない祖先を参照しにくくなります。

.article-card-area {
  container: article-card / inline-size;
}

@container article-card (width >= 640px) {
  .article-card {
    grid-template-columns: 280px 1fr;
  }
}

実装例1:記事カードをコンテナ幅で切り替える

記事カードはContainer Queryと相性が良いパーツです。同じカードでも、狭い場所では縦積み、広い場所では画像と本文を横並びにできます。

<div class="post-card-wrap">
  <article class="post-card">
    <img src="thumb.jpg" alt="">
    <div>
      <p class="post-card__tag">CSS</p>
      <h2>Container Query の使い方</h2>
      <p>コンテナ幅に応じてカードの見せ方を変えます。</p>
    </div>
  </article>
</div>
.post-card-wrap {
  container: post-card / inline-size;
}

.post-card {
  display: grid;
  gap: 16px;
}

.post-card img {
  width: 100%;
  aspect-ratio: 16 / 9;
  object-fit: cover;
}

@container post-card (min-width: 640px) {
  .post-card {
    grid-template-columns: 240px 1fr;
    align-items: center;
  }
}

実装例2:サイドバー内だけ小さく見せる

カードをサイドバーへ置くと、viewportは広いのにカード領域だけ狭いという状況が起きます。media queryだけだと「PCだから横並び」と判断してしまい、窮屈なUIになりがちです。

.related-posts {
  container: related / inline-size;
}

.related-card {
  display: grid;
  gap: 12px;
}

@container related (min-width: 520px) {
  .related-card {
    grid-template-columns: 160px 1fr;
  }
}

コンポーネントが置かれた場所の幅を自分で判断できるため、ページ全体のブレイクポイントへ依存しすぎない設計になります。

実装例3:コンテナ単位で文字サイズを変える

Container Queryにはcqiなどのコンテナクエリ単位もあります。1cqiはコンテナのinline-sizeの1%です。

.hero-panel {
  container-type: inline-size;
}

.hero-panel h1 {
  font-size: clamp(2rem, 8cqi, 5rem);
}

viewport単位のvwよりも、コンポーネントの実サイズに沿った文字調整ができます。ただし小さなコンテナでは変化が大きく見えるので、clamp()で最小値と最大値を必ず決めるのがおすすめです。

実際にやってみた

See the Pen CSS container query の使い方 by dipcode_kj (@dipcode_kj) on CodePen.

よくある失敗

  • 基準になる親へcontainer-typeを書いていない:@containerだけを書いても、参照できるコンテナがなければ効きません。
  • 親自身を@container内で直接変えようとする:Container Queryは基本的にコンテナの子孫をスタイルするためのものです。
  • widthとinline-sizeを混同する:多言語・縦書きまで考えるならinline-sizeの理解が必要です。
  • media queryを全廃しようとする:ページ全体の大枠はmedia query、部品の中身はcontainer query、と分けると扱いやすいです。
  • コンテナ名を付けずに入れ子で使う:最寄りのコンテナを参照して意図とずれる場合があります。
  • コンテンツ量の増加を見ていない:横並びになった時にタイトルや説明文が窮屈にならないか確認します。

実務での使い分け

  • media query:ページ全体のカラム数、ヘッダー、余白、PC/SPの大きな切り替えに使う
  • container query:カード、一覧、関連記事、プロフィール、CTAなど再利用部品の内部レイアウトに使う
  • clamp():コンテナ幅に合わせて文字や余白をなめらかに調整する

まとめ

Container Queryは、レスポンシブ設計を「画面幅」から「コンポーネントが実際に使える幅」へ近づけてくれます。特に記事カード、商品カード、プロフィール、関連記事のような再利用パーツでは効果が大きいです。

まずは親にcontainer: name / inline-size;を指定し、@container name (min-width: ...)で子要素の見せ方を変えるところから始めてください。media queryと置き換えるというより、役割を分けて併用するのが現実的です。

参考資料