コンテナクエリ
この章では、Tailwind CSS v4 で標準サポートされたコンテナクエリを学びます。
コンテナクエリとは
コンテナクエリは、ビューポートではなく親コンテナのサイズに基づいてスタイルを適用する機能です。
<!-- 従来のメディアクエリ: ビューポート幅に依存 -->
<div class="md:flex">...</div>
<!-- コンテナクエリ: コンテナ幅に依存 -->
<div class="@container">
<div class="@md:flex">...</div>
</div>
基本的な使い方
コンテナの定義
@container クラスでコンテナを定義します。
<div class="@container">
<div class="@md:flex @lg:grid @lg:grid-cols-2">
コンテナサイズに応じたレイアウト
</div>
</div>
コンテナブレークポイント
| プレフィックス | 最小幅 |
|---|---|
@3xs | 16rem (256px) |
@2xs | 18rem (288px) |
@xs | 20rem (320px) |
@sm | 24rem (384px) |
@md | 28rem (448px) |
@lg | 32rem (512px) |
@xl | 36rem (576px) |
@2xl | 42rem (672px) |
@3xl | 48rem (768px) |
@4xl | 56rem (896px) |
@5xl | 64rem (1024px) |
@6xl | 72rem (1152px) |
@7xl | 80rem (1280px) |
<div class="@container">
<div class="block @sm:flex @lg:grid @lg:grid-cols-3">
レスポンシブなレイアウト
</div>
</div>
名前付きコンテナ
複数のコンテナを区別するために名前を付けることができます。
<div class="@container/main">
<div class="@container/sidebar">
<div class="@lg/main:flex @md/sidebar:block">
名前付きコンテナを参照
</div>
</div>
</div>
@max-* バリアント
@max-* バリアントを使うと、コンテナ幅が指定値未満のときにスタイルを適用できます。
<div class="@container">
<div class="flex flex-row @max-md:flex-col">
コンテナ幅が 448px (28rem) 未満で縦並び
</div>
</div>
@sm:@max-md:flex のように通常のバリアントと重ねると、範囲指定もできます。
任意の値
<div class="@container">
<div class="@[500px]:flex">
500px 以上で flex
</div>
</div>
コンテナクエリ vs メディアクエリ
メディアクエリの問題点
<!-- メディアクエリ: サイドバーがある場合、カードが狭くても横並びになる -->
<div class="grid grid-cols-1 md:grid-cols-2">
<Card />
<Card />
</div>
コンテナクエリの解決策
<!-- コンテナクエリ: カード自体の幅に応じてレイアウト変更 -->
<div class="@container">
<div class="block @md:flex gap-4">
<Card />
<Card />
</div>
</div>
実践例
レスポンシブカード
<article class="@container bg-white rounded-xl shadow-lg overflow-hidden">
<div class="@md:flex">
<!-- 画像 -->
<div class="@md:w-1/3 @lg:w-1/4">
<img
src="..."
class="w-full h-48 @md:h-full object-cover"
/>
</div>
<!-- コンテンツ -->
<div class="p-6 @md:w-2/3 @lg:w-3/4">
<span class="text-sm text-blue-600 font-semibold">カテゴリ</span>
<h2 class="mt-2 text-xl @lg:text-2xl font-bold">タイトル</h2>
<p class="mt-2 text-gray-600 @lg:text-lg">
説明文がここに入ります...
</p>
<div class="mt-4 flex flex-col @sm:flex-row gap-2">
<button class="px-4 py-2 bg-blue-500 text-white rounded-sm">
詳細
</button>
<button class="px-4 py-2 border border-gray-300 rounded-sm">
保存
</button>
</div>
</div>
</div>
</article>
ダッシュボードウィジェット
<div class="@container bg-white rounded-lg shadow-sm p-4">
<div class="@xs:flex @xs:justify-between @xs:items-center mb-4">
<h3 class="font-bold text-lg">売上統計</h3>
<span class="text-sm text-gray-500">過去 30 日間</span>
</div>
<div class="grid grid-cols-1 @sm:grid-cols-2 @lg:grid-cols-4 gap-4">
<div class="p-4 bg-blue-50 rounded-lg">
<p class="text-sm text-blue-600">総売上</p>
<p class="text-2xl font-bold">¥1,234,567</p>
</div>
<div class="p-4 bg-green-50 rounded-lg">
<p class="text-sm text-green-600">注文数</p>
<p class="text-2xl font-bold">1,234</p>
</div>
<div class="p-4 bg-yellow-50 rounded-lg">
<p class="text-sm text-yellow-600">平均単価</p>
<p class="text-2xl font-bold">¥12,345</p>
</div>
<div class="p-4 bg-purple-50 rounded-lg">
<p class="text-sm text-purple-600">リピート率</p>
<p class="text-2xl font-bold">45.6%</p>
</div>
</div>
</div>
サイドバー + メインコンテンツ
<div class="flex">
<!-- サイドバー -->
<aside class="w-64 shrink-0">
<nav class="p-4">サイドバー</nav>
</aside>
<!-- メインコンテンツ (コンテナクエリを使用) -->
<main class="flex-1 @container p-4">
<div class="grid grid-cols-1 @md:grid-cols-2 @xl:grid-cols-3 gap-6">
<!-- カード -->
<div class="@container bg-white rounded-lg shadow-sm">
<div class="@xs:flex p-4">
<img src="..." class="w-full @xs:w-20 h-20 object-cover rounded-sm" />
<div class="mt-2 @xs:mt-0 @xs:ml-4">
<h3 class="font-bold">タイトル</h3>
<p class="text-sm text-gray-600">説明...</p>
</div>
</div>
</div>
<!-- 繰り返し -->
</div>
</main>
</div>
プロダクトカード
<div class="@container group bg-white rounded-xl shadow-lg overflow-hidden">
<!-- 画像セクション -->
<div class="relative @lg:flex">
<div class="@lg:w-1/2">
<img
src="..."
class="w-full aspect-square @lg:aspect-auto @lg:h-full object-cover"
/>
</div>
<!-- 詳細セクション -->
<div class="p-6 @lg:w-1/2 @lg:flex @lg:flex-col @lg:justify-center">
<div class="flex items-center gap-2 mb-2">
<span class="px-2 py-1 bg-blue-100 text-blue-800 text-xs rounded-full">
新着
</span>
<span class="text-sm text-gray-500">SKU: 12345</span>
</div>
<h2 class="text-xl @md:text-2xl font-bold">
プロダクト名
</h2>
<p class="mt-2 text-gray-600 @md:text-lg line-clamp-3 @lg:line-clamp-none">
商品の詳細説明がここに入ります。長いテキストの場合は
小さいコンテナではクランプされます。
</p>
<div class="mt-4 @sm:flex @sm:items-center @sm:justify-between">
<div>
<span class="text-2xl font-bold text-blue-600">¥12,800</span>
<span class="ml-2 text-sm text-gray-400 line-through">¥15,800</span>
</div>
<button class="mt-4 @sm:mt-0 w-full @sm:w-auto px-6 py-2 bg-blue-500 hover:bg-blue-600 text-white rounded-lg">
カートに追加
</button>
</div>
</div>
</div>
</div>
検索結果アイテム
<div class="@container">
<article class="@md:flex gap-4 p-4 bg-white rounded-lg shadow-sm hover:shadow-md transition-shadow">
<!-- サムネイル -->
<div class="@md:w-48 @md:shrink-0">
<img
src="..."
class="w-full h-48 @md:h-32 object-cover rounded-sm"
/>
</div>
<!-- コンテンツ -->
<div class="mt-4 @md:mt-0 flex-1">
<div class="@lg:flex @lg:justify-between @lg:items-start">
<div>
<h3 class="font-bold text-lg hover:text-blue-600">
検索結果タイトル
</h3>
<p class="mt-1 text-sm text-gray-500">
投稿者: ユーザー名 • 3 時間前
</p>
</div>
<div class="mt-2 @lg:mt-0 flex gap-2">
<span class="px-2 py-1 bg-gray-100 text-gray-600 text-xs rounded-sm">
タグ 1
</span>
<span class="px-2 py-1 bg-gray-100 text-gray-600 text-xs rounded-sm">
タグ 2
</span>
</div>
</div>
<p class="mt-2 text-gray-600 line-clamp-2 @lg:line-clamp-3">
検索結果の説明文がここに入ります...
</p>
<div class="mt-4 flex items-center gap-4 text-sm text-gray-500">
<span>👍 123</span>
<span>💬 45</span>
<span>👁 1.2k</span>
</div>
</div>
</article>
</div>
コンテナクエリのベストプラクティス
1. コンポーネントを自己完結させる
<!-- Good: コンポーネント内でコンテナを定義 -->
<div class="@container">
<div class="@md:flex">...</div>
</div>
<!-- Avoid: 親に依存 -->
<div class="md:flex">...</div>
2. 適切なブレークポイントを選択
<!-- コンポーネントのサイズに合わせたブレークポイント -->
<div class="@container max-w-md">
<div class="@xs:flex">小さいコンテナ用</div>
</div>
<div class="@container max-w-4xl">
<div class="@lg:grid @lg:grid-cols-3">大きいコンテナ用</div>
</div>
3. ネストに注意
<!-- 名前付きコンテナで明確に -->
<div class="@container/outer">
<div class="@container/inner">
<div class="@md/outer:flex @sm/inner:block">
明確な参照
</div>
</div>
</div>
まとめ
@containerでコンテナを定義@sm:/@md:/@lg:等でコンテナサイズに応じたスタイル@max-md:等の@max-*バリアントで上限方向の指定も可能- 名前付きコンテナで複数コンテナを区別
- コンポーネントベースの開発に最適
- メディアクエリと組み合わせて使用可能
次に読む
- アニメーション —
transition/animate-*で動きを加える - コンポーネントパターン — 実用 UI 部品の Tailwind 実装
- Tailwind CSS ガイド 目次 — 全 18 章の構成に戻る