📦
メディアクエリの限界を超える!CSS Container Queries完全ガイド
はじめに:メディアクエリの限界
レスポンシブデザインといえば、長年メディアクエリが主役でした。
しかし、メディアクエリには致命的な欠点があります。
/* メディアクエリは viewport の幅でしか判断できない */
@media (min-width: 768px) {
.card {
display: flex; /* タブレット以上は横並び */
}
}
この何が問題なのでしょうか?
問題1:コンポーネントの配置場所に依存してしまう
例えば、以下のようなカードコンポーネントがあるとします:
<!-- メインエリア(広い)に配置 -->
<main class="main-area">
<div class="card">...</div>
</main>
<!-- サイドバー(狭い)に配置 -->
<aside class="sidebar">
<div class="card">...</div>
</aside>
メディアクエリの場合:
- viewport が768px以上なら、どちらのカードも横並びレイアウトになる
- サイドバーのカードは狭いのに、無理やり横並びになってレイアウトが崩れる
本当にやりたいこと:
- カードの親要素の幅に応じてレイアウトを変えたい
- メインエリアのカードは横並び
- サイドバーのカードは縦並び(親が狭いから)
これがメディアクエリの限界です。
問題2:コンポーネントの再利用性が低い
/* このカードはメインエリア専用になってしまう */
.main-area .card {
display: flex;
}
/* サイドバー用に別のスタイルが必要... */
.sidebar .card {
display: block;
}
配置場所ごとにスタイルを書く必要があり、コンポーネント指向の設計ができません。
CSS Container Queries が解決する
Container Queries を使えば、親要素の幅に応じてスタイルを変えられます。
/* 親要素をコンテナとして定義 */
.card-container {
container-type: inline-size;
}
/* 親の幅が400px以上なら横並び */
@container (min-width: 400px) {
.card {
display: flex;
}
}
これで:
- メインエリアのカードは横並び(親が広いから)
- サイドバーのカードは縦並び(親が狭いから)
- 同じCSSで、配置場所に関係なく適切なレイアウトになる
基本的な使い方
ステップ1:親要素をコンテナとして定義
.container {
container-type: inline-size; /* この要素をコンテナにする */
}
ステップ2:@containerルールを書く
@container (min-width: 400px) {
/* コンテナの幅が400px以上の時のスタイル */
.card {
display: flex;
}
}
完全な例
<div class="card-container">
<div class="card">
<img src="image.jpg" alt="">
<div class="content">
<h2>タイトル</h2>
<p>説明文...</p>
</div>
</div>
</div>
/* 親をコンテナとして定義 */
.card-container {
container-type: inline-size;
}
/* デフォルト:縦並び */
.card {
display: block;
}
.card img {
width: 100%;
height: 200px;
object-fit: cover;
}
/* コンテナの幅が400px以上:横並び */
@container (min-width: 400px) {
.card {
display: flex;
gap: 1rem;
}
.card img {
width: 200px;
height: auto;
}
}
container-type の種類と使い分け
container-type には3つの値があります:
1. inline-size(⭐ 最もよく使う)
.container {
container-type: inline-size;
}
- インライン方向(通常は幅)のみをコンテナサイズとして扱う
- 高さは無視される
- パフォーマンスが良い(高さの再計算が不要)
- 99%のケースでこれを使えばOK
2. size
.container {
container-type: size;
}
- 幅と高さの両方をコンテナサイズとして扱う
- 高さにも依存したレイアウトが必要な場合
- パフォーマンスに注意(レイアウトシフトのリスク)
3. normal(デフォルト)
.container {
container-type: normal;
}
- コンテナクエリを使わない(通常の要素)
- 明示的に書く必要はない
container-name でターゲット指定
複数のコンテナが入れ子になっている場合、どのコンテナに対してクエリを書くか指定できます。
/* 名前付きコンテナ */
.sidebar {
container-type: inline-size;
container-name: sidebar;
}
.main {
container-type: inline-size;
container-name: main;
}
/* sidebarコンテナに対するクエリ */
@container sidebar (min-width: 300px) {
.widget {
padding: 1rem;
}
}
/* mainコンテナに対するクエリ */
@container main (min-width: 800px) {
.article {
columns: 2;
}
}
省略記法:
.sidebar {
/* container-type と container-name を同時に指定 */
container: sidebar / inline-size;
}
実際に動くデモを見てみよう
デモ1:カードコンポーネント(メイン+サイドバー)
デモ2:Container Query Units(cqw)の実用例
実用パターン1:カードコンポーネント
.card-container {
container-type: inline-size;
}
/* デフォルト:モバイル(縦並び) */
.card {
display: block;
}
.card img {
width: 100%;
}
/* 親が400px以上:タブレット(横並び) */
@container (min-width: 400px) {
.card {
display: flex;
gap: 1rem;
}
.card img {
width: 150px;
flex-shrink: 0;
}
}
/* 親が600px以上:デスクトップ(大きめレイアウト) */
@container (min-width: 600px) {
.card {
gap: 2rem;
}
.card img {
width: 250px;
}
.card h2 {
font-size: 2rem;
}
}
実用パターン2:グリッドの列数に応じた調整
.grid-container {
container-type: inline-size;
}
.grid {
display: grid;
gap: 1rem;
}
/* デフォルト:1列 */
.grid {
grid-template-columns: 1fr;
}
/* 親が400px以上:2列 */
@container (min-width: 400px) {
.grid {
grid-template-columns: repeat(2, 1fr);
}
}
/* 親が800px以上:3列 */
@container (min-width: 800px) {
.grid {
grid-template-columns: repeat(3, 1fr);
}
}
/* 親が1200px以上:4列 */
@container (min-width: 1200px) {
.grid {
grid-template-columns: repeat(4, 1fr);
}
}
Container Query Units(コンテナ単位)
Container Queries には、コンテナの幅に応じた相対単位もあります。
| 単位 | 説明 |
|---|---|
cqw |
コンテナの幅の1% |
cqh |
コンテナの高さの1% |
cqi |
コンテナのインラインサイズ(幅)の1% |
cqb |
コンテナのブロックサイズ(高さ)の1% |
cqmin |
cqi と cqb の小さい方 |
cqmax |
cqi と cqb の大きい方 |
実用例:フォントサイズをコンテナに応じて調整
.card-container {
container-type: inline-size;
}
.card h2 {
/* コンテナの幅に応じてフォントサイズを調整 */
font-size: clamp(1rem, 5cqw, 3rem);
}
.card p {
font-size: clamp(0.875rem, 3cqw, 1.125rem);
}
メリット:
-
@containerルールを書かなくても、自動的にサイズが調整される - よりスムーズなレスポンシブデザインが実現できる
メディアクエリとの使い分け
メディアクエリを使うべき場面
-
グローバルなレイアウト変更
- サイドバーの表示/非表示
- ヘッダーのレイアウト変更
- ページ全体のグリッド構造
/* グローバルレイアウト */
@media (min-width: 768px) {
.page {
display: grid;
grid-template-columns: 250px 1fr;
}
}
Container Queriesを使うべき場面
-
コンポーネント単位のレイアウト変更
- カードコンポーネント
- ボタングループ
- ナビゲーションメニュー
/* コンポーネント */
.card-container {
container-type: inline-size;
}
@container (min-width: 400px) {
.card {
display: flex;
}
}
併用パターン
/* グローバル:タブレット以上でサイドバー表示 */
@media (min-width: 768px) {
.layout {
display: grid;
grid-template-columns: 250px 1fr;
}
}
/* コンポーネント:親の幅に応じてカードを調整 */
.card-container {
container-type: inline-size;
}
@container (min-width: 400px) {
.card {
display: flex;
}
}
パフォーマンスへの影響
container-type: inline-size は安全
- 高さの再計算が不要なので、パフォーマンスへの影響はほぼない
- レイアウトシフトのリスクも低い
container-type: size は注意が必要
- 高さも含めてコンテナサイズとして扱うため、レイアウトの再計算が発生しやすい
- 特に、コンテンツの高さが動的に変わる場合は注意
- 必要な場合のみ使う
ベストプラクティス
/* ✅ 推奨:inline-size を使う */
.container {
container-type: inline-size;
}
/* ⚠️ 注意:size は必要な場合のみ */
.special-container {
container-type: size;
height: 100vh; /* 高さを固定する */
}
ブラウザサポート状況
2023年2月以降、主要ブラウザでサポート開始
| ブラウザ | サポート開始 |
|---|---|
| Chrome | 105+(2022年8月) |
| Edge | 105+(2022年9月) |
| Safari | 16.0+(2022年9月) |
| Firefox | 110+(2023年2月) |
2025年現在:もう安心して使えます!
フォールバック戦略
古いブラウザのサポートが必要な場合:
/* フォールバック:メディアクエリ */
@media (min-width: 400px) {
.card {
display: flex;
}
}
/* Container Queries対応ブラウザ */
@supports (container-type: inline-size) {
.card-container {
container-type: inline-size;
}
@container (min-width: 400px) {
.card {
display: flex;
}
}
}
まとめ
Container Queriesを使うべき理由
-
コンポーネントの再利用性が劇的に向上
- 配置場所に依存しないスタイル
- 同じコンポーネントをどこにでも使える
-
メディアクエリより柔軟
- viewport ではなく親要素の幅で判断
- より細かい制御が可能
-
コンポーネント指向の設計に必須
- React/Vue などのコンポーネントフレームワークと相性抜群
- デザインシステムの構築が容易に
-
もう安心して使える
- 主要ブラウザで2年以上サポート
- パフォーマンスも問題なし
今日から使えるチェックリスト
-
カードコンポーネントを
@containerで実装してみる - メディアクエリを Container Queries に置き換えられる箇所を探す
-
コンテナ単位(
cqwなど)を使ってフォントサイズを調整してみる - デザインシステムに Container Queries を組み込む
Container Queries は、レスポンシブデザインの新しいスタンダードです。
ぜひ今日から使ってみてください!
Discussion