DevToolBoxFREE
BlogAdvertise

CSS Container Queries 完全ガイド 2026

13分by DevToolBox

CSS コンテナクエリはメディアクエリ以来のレスポンシブデザインにおける最も重要な進歩です。ビューポートサイズではなく、親コンテナのサイズに応答するコンポーネントを構築できます。

コンテナクエリとは?

コンテナクエリはビューポートではなく、コンテナ要素のサイズに基づいてスタイルを適用します。

/* The Problem: A card component in different contexts */

/* In main content (800px wide) → horizontal layout */
/* In sidebar (300px wide) → vertical layout */
/* In footer (200px wide) → minimal layout */

/* With media queries, you cannot distinguish these contexts
   because they all exist at the same viewport width.

   With container queries, each container context triggers
   different styles automatically. */

コンテナクエリ vs メディアクエリ

メディアクエリはビューポートサイズにのみ応答します。コンテナクエリはこの制限を解決します。

FeatureMedia QueriesContainer Queries
Responds toViewport sizeContainer size
ScopeGlobal (page-level)Local (component-level)
ReusabilityBreaks in different contextsWorks in any context
Use casePage layoutComponent layout
Unitsvw, vh, vmin, vmaxcqw, cqh, cqi, cqb
Browser supportUniversalAll modern browsers (2023+)

コンテインメントの理解

コンテナクエリにはコンテインメントが必要です。

コンテインメントタイプ

/* container-type values */

/* inline-size: Containment on the inline axis only (width) */
/* Most common — use this in most cases */
.card-wrapper {
  container-type: inline-size;
}

/* size: Containment on both inline and block axes (width + height) */
/* Use when you need to query both dimensions */
.widget-wrapper {
  container-type: size;
}

/* normal (default): No containment — cannot be queried */
.regular-div {
  container-type: normal; /* This is the default */
}

/* IMPORTANT: container-type: size prevents auto-height behavior.
   The element will not grow to fit its content on the block axis.
   Use inline-size unless you specifically need height queries. */

コンテナクエリ構文

基本構文は container-type でコンテナを定義し、@container でクエリを記述します。

/* Step 1: Define a container */
.card-container {
  container-type: inline-size;
}

/* Step 2: Write container queries */
.card {
  /* Default styles (smallest) */
  display: grid;
  gap: 12px;
  padding: 16px;
}

.card__image {
  width: 100%;
  aspect-ratio: 16/9;
  border-radius: 8px;
  object-fit: cover;
}

.card__title {
  font-size: 1rem;
  font-weight: 700;
}

/* When container is at least 400px wide */
@container (min-width: 400px) {
  .card {
    grid-template-columns: 200px 1fr;
    align-items: center;
  }
  .card__title {
    font-size: 1.25rem;
  }
}

/* When container is at least 600px wide */
@container (min-width: 600px) {
  .card {
    grid-template-columns: 280px 1fr;
    gap: 24px;
    padding: 24px;
  }
  .card__title {
    font-size: 1.5rem;
  }
  .card__description {
    display: block; /* Show description only in wide containers */
  }
}

名前付きコンテナ

特定の祖先をターゲットにするためにコンテナに名前を付けられます。

/* Name containers to target specific ancestors */
.sidebar {
  container-type: inline-size;
  container-name: sidebar;
}

.main-content {
  container-type: inline-size;
  container-name: main;
}

/* Query a specific named container */
@container sidebar (max-width: 300px) {
  .widget {
    font-size: 0.875rem;
  }
}

@container main (min-width: 800px) {
  .article-card {
    grid-template-columns: 1fr 1fr;
  }
}

/* Without a name, @container queries the NEAREST ancestor
   with containment. Named queries skip to the named container. */

container ショートハンド

container-type と container-name を1つの宣言にまとめます。

/* Shorthand: container: <name> / <type> */
.sidebar {
  container: sidebar / inline-size;
}

/* Equivalent to: */
.sidebar {
  container-name: sidebar;
  container-type: inline-size;
}

/* Multiple names (for querying by either name) */
.widget-area {
  container: widget-area panel / inline-size;
}

コンテナクエリ単位

コンテナ寸法に相対的な新しい CSS 単位が導入されました。

UnitDescriptionEquivalent
cqw1% of container widthSimilar to vw for viewport
cqh1% of container heightSimilar to vh for viewport
cqi1% of container inline sizeWidth in horizontal writing
cqb1% of container block sizeHeight in horizontal writing
cqminSmaller of cqi and cqbSimilar to vmin
cqmaxLarger of cqi and cqbSimilar to vmax
/* Fluid typography with container query units */
.card-title {
  /* Font size scales with container width */
  /* Minimum 1rem, maximum 2rem, scales at 5cqi */
  font-size: clamp(1rem, 5cqi, 2rem);
}

.card-padding {
  /* Responsive padding based on container */
  padding: clamp(12px, 4cqi, 32px);
}

.hero-text {
  /* Large text that scales with its container */
  font-size: clamp(2rem, 8cqi, 5rem);
  line-height: 1.1;
}

実践例

レスポンシブカード

コンテナの空間に適応するカードコンポーネント。

/* Responsive card component */
.card-container {
  container: card / inline-size;
}

.card {
  display: flex;
  flex-direction: column;
  gap: 12px;
  padding: 16px;
  border-radius: 12px;
  background: var(--card-bg);
  border: 1px solid var(--border-color);
}

.card__image {
  width: 100%;
  aspect-ratio: 16 / 9;
  object-fit: cover;
  border-radius: 8px;
}

.card__meta {
  display: none; /* Hidden in small containers */
}

.card__actions {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
}

/* Medium card (400px+) — side-by-side layout */
@container card (min-width: 400px) {
  .card {
    flex-direction: row;
    align-items: flex-start;
  }
  .card__image {
    width: 180px;
    flex-shrink: 0;
    aspect-ratio: 1;
  }
  .card__meta {
    display: flex;
    gap: 12px;
    font-size: 0.875rem;
    color: var(--text-muted);
  }
}

/* Large card (700px+) — featured layout */
@container card (min-width: 700px) {
  .card {
    flex-direction: column;
    padding: 0;
    overflow: hidden;
  }
  .card__image {
    width: 100%;
    height: 300px;
    border-radius: 0;
  }
  .card__content {
    padding: 24px;
  }
  .card__title {
    font-size: 1.75rem;
  }
}

レスポンシブナビ

コンテナ幅に基づいてレイアウトを切り替えるナビゲーション。

/* Navigation that adapts to its container */
.nav-container {
  container: nav / inline-size;
}

.nav {
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.nav__item {
  padding: 8px 12px;
  border-radius: 6px;
  font-size: 0.875rem;
}

.nav__item-icon {
  display: none;
}

/* Horizontal layout when container is wide enough */
@container nav (min-width: 500px) {
  .nav {
    flex-direction: row;
    gap: 8px;
  }
  .nav__item {
    white-space: nowrap;
  }
}

/* Show icons when there is more space */
@container nav (min-width: 700px) {
  .nav__item-icon {
    display: inline-flex;
    margin-right: 6px;
  }
  .nav__item {
    padding: 10px 16px;
  }
}

適応グリッドアイテム

グリッド列幅に基づいてレイアウトを変更。

/* Grid items that adapt to their column width */
.grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
  gap: 24px;
}

/* Each grid item is a container */
.grid__item {
  container: grid-item / inline-size;
}

.product {
  text-align: center;
  padding: 16px;
}

.product__price {
  font-size: 1.5rem;
  font-weight: 700;
}

.product__details {
  display: none;
}

@container grid-item (min-width: 350px) {
  .product {
    display: grid;
    grid-template-columns: 120px 1fr;
    text-align: left;
    gap: 16px;
  }
  .product__details {
    display: block;
  }
}

スタイルコンテナクエリ

コンテナの計算されたスタイル値をクエリできます。

/* Style container queries — query computed style values */

/* Define a container with a custom property */
.theme-container {
  container-type: normal; /* No size containment needed for style queries */
  --theme: light;
}

.theme-container.dark {
  --theme: dark;
}

/* Query the custom property value */
@container style(--theme: dark) {
  .card {
    background: #1a1a2e;
    color: #e0e0e0;
    border-color: #333;
  }
  .button {
    background: #4a90d9;
    color: white;
  }
}

@container style(--theme: light) {
  .card {
    background: #ffffff;
    color: #333;
    border-color: #e0e0e0;
  }
}

/* Practical use: component variants via CSS properties */
.alert-container {
  --variant: info;
}

@container style(--variant: error) {
  .alert {
    background: #fef2f2;
    border-left: 4px solid #ef4444;
    color: #991b1b;
  }
}

@container style(--variant: success) {
  .alert {
    background: #f0fdf4;
    border-left: 4px solid #22c55e;
    color: #166534;
  }
}

ネストされたコンテナクエリ

複数の祖先コンテナに基づく複雑なレスポンシブ動作。

/* Nested container queries */
.page {
  container: page / inline-size;
}

.sidebar {
  container: sidebar / inline-size;
}

/* Different behavior based on multiple container sizes */
@container page (min-width: 1200px) {
  .sidebar {
    width: 350px;
  }
}

@container sidebar (max-width: 250px) {
  .sidebar-widget {
    font-size: 0.875rem;
    padding: 8px;
  }
  .sidebar-widget__title {
    font-size: 1rem;
  }
}

@container sidebar (min-width: 300px) {
  .sidebar-widget {
    padding: 16px;
  }
  .sidebar-widget__chart {
    display: block;
  }
}

デザインパターン

固有レスポンシブデザイン

CSS Grid auto-fit と組み合わせます。

/* Intrinsic design: Grid + Container Queries */
.auto-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: 24px;
}

.auto-grid > * {
  container-type: inline-size;
}

/* Items automatically adapt as the grid reflows */
/* No breakpoints needed — the grid column width drives the layout */
@container (min-width: 400px) {
  .feature-card {
    grid-template-columns: auto 1fr;
  }
}

@container (min-width: 500px) {
  .feature-card__description {
    font-size: 1.125rem;
  }
}

ダッシュボードウィジェット

グリッドセルに適応するウィジェットパターン。

/* Dashboard widget pattern */
.dashboard {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
  gap: 20px;
}

.dashboard__cell {
  container: widget / inline-size;
}

.widget {
  padding: 16px;
  border-radius: 12px;
  background: var(--widget-bg);
}

.widget__chart {
  height: 150px;
}

.widget__table {
  display: none; /* Hidden in small widgets */
}

@container widget (min-width: 400px) {
  .widget__chart {
    height: 200px;
  }
  .widget__stats {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 12px;
  }
}

@container widget (min-width: 600px) {
  .widget {
    padding: 24px;
  }
  .widget__table {
    display: table;
  }
  .widget__chart {
    height: 280px;
  }
}

ブラウザサポート

2026年時点で優れたブラウザサポート。

フォールバック戦略

@supports で優雅なフォールバックを提供。

/* Graceful fallback with @supports */
.card-container {
  /* Fallback: use media queries */
}

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

/* Fallback styles using media queries */
@media (min-width: 768px) {
  .card {
    grid-template-columns: 200px 1fr;
  }
}

/* Container query override (when supported) */
@container (min-width: 400px) {
  .card {
    grid-template-columns: 200px 1fr;
  }
}

パフォーマンス考慮事項

コンテインメントの理解が重要です。

  • 新しいスタッキングコンテキストを作成。
  • 不要なネストを避ける。
  • 幅のみの場合は inline-size を使用。
  • 追加のレイアウトパスは発生しない。
  • 名前付きコンテナで制御。

ベストプラクティス

  1. コンポーネントにコンテナクエリ、ページにメディアクエリ。
  2. inline-size から始める。
  3. コンテナに名前を付ける。
  4. コンテナクエリ単位を使用。
  5. Grid と Flexbox と組み合わせる。
  6. モバイルファーストで設計。
  7. @supports でフォールバック。

メディアクエリからの移行

すべてのメディアクエリを置き換える必要はありません。

/* Decision Guide: Container Query vs Media Query */

/* USE CONTAINER QUERIES when:
   ✅ Component is reused in different layout contexts
   ✅ Component goes in sidebars, modals, grids, etc.
   ✅ You need component-level responsive behavior
   ✅ The component's layout depends on available space

   USE MEDIA QUERIES when:
   ✅ Changing the overall page layout
   ✅ Showing/hiding entire sections
   ✅ Adjusting global typography or spacing
   ✅ Changing navigation from desktop to mobile
   ✅ Print stylesheets

   USE BOTH when:
   ✅ Page layout switches at viewport breakpoints (media query)
   ✅ Components within the layout adapt to their containers (container query)
*/

結論

CSS コンテナクエリはレスポンシブデザインの考え方を根本的に変えます。モダンな CSS レイアウトテクニックと組み合わせて、よりモジュラーで保守しやすいデザインシステムを構築しましょう。

FAQ

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

メディアクエリはビューポート、コンテナクエリは親コンテナに応答します。

すべての親要素に container-type が必要?

いいえ。クエリコンテナにしたい要素のみに設定します。

Grid や Flexbox と使える?

はい、シームレスに動作します。

inline-size と size の違いは?

inline-size はインライン軸のみ、size は両軸にコンテインメントを作成します。

𝕏 Twitterin LinkedIn
この記事は役に立ちましたか?

Stay Updated

Get weekly dev tips and new tool announcements.

No spam. Unsubscribe anytime.

Partner Picks

Sponsor this article

Place your product next to this developer topic with tracked clicks.

Ask about article sponsorship

Related Articles

This site uses cookies for analytics and to display ads. By continuing to browse, you agree. Privacy Policy