コンテナクエリ:画面サイズではなく、コンポーネントが「自らの配置場所」を認識する仕組み

Development tutorial - IT technology blog
Development tutorial - IT technology blog

メディアクエリはもはや唯一の選択肢ではない

メディアクエリは10年以上にわたりレスポンスWebデザインの主役でした。しかし、この手法には大きな制限があります。それは「ビューポート(画面サイズ)」しか考慮しない点です。そのため、同じコンポーネントを異なる場所に再利用したい場合に課題が生じます。

例えば、商品紹介用の「カード型コンポーネント」を考えてみましょう。デスクトップでは3カラムのグリッド内で綺麗に表示されます。しかし、同じカードを幅の狭いサイドバーに配置した場合、メディアクエリは役に立ちません。画面が1920pxあっても、カードが使える実際のスペースは300px程度しかないからです。その結果、レイアウトが崩れたり、枠からはみ出したりしてしまいます。

最近のダッシュボード開発プロジェクトで、私たちのチームは .card--sidebar.card--small といった大量のクラスを管理しなければなりませんでした。コンテナクエリに移行したことで、不要なCSSロジックの約40%を削減できました。コンポーネント自身が「もし親要素の幅が400px以上なら横並びに、それ以下なら自動的に縦並びにする」と判断できるようになったからです。

言い換えれば、コンポーネントがブラウザに受動的に従うのではなく、自らのスペースを自覚する能力を持ったのです。

コンテナクエリを実装する2つのステップ

現在、コンテナクエリは世界の主要なブラウザの91%以上でサポートされています(CanIUse調べ)。ライブラリを追加することなく、素のCSSで直接利用可能です。設定は非常にシンプルです。

まず、親要素を「コンテナ(器)」として定義します:

.parent-container {
  /* この要素を子要素のための「物差し」にする */
  container-type: inline-size;
  
  /* 複数のコンテナが重なる場合の混乱を防ぐために名前を付ける */
  container-name: product-grid;
}

inline-size は最も一般的な選択肢です。これにより、子要素は親の幅(width)をチェックできるようになります。size を使用すると高さもチェックできますが、その場合は親要素に高さを固定値で指定する必要があります。

「すべてを察する」コンポーネントの構築

インテリジェントなカードコンポーネントを実際に作ってみましょう。目標は、レイアウトのどこに配置されても自己変形できるようにすることです。

1. 基本的なHTML構造

<div class="card-wrapper">
  <div class="custom-card">
    <img src="thumb.jpg" alt="Product">
    <div class="content">
      <h2>商品名</h2>
      <p>商品の詳細説明...</p>
    </div>
  </div>
</div>

2. ラッパーをコンテナにする

.card-wrapper {
  container-type: inline-size;
  width: 100%;
}

3. コンポーネント用のクエリを書く

@media の代わりに @container を使用します。この書き方により、表示ロジックをコンポーネントに直接紐付けることができます。

/* デフォルトスタイル:狭いスペース用の縦並び */
.custom-card {
  display: flex;
  flex-direction: column;
  gap: 16px;
}

/* コンテナの幅が500px以上の場合 */
@container (min-width: 500px) {
  .custom-card {
    flex-direction: row;
    align-items: center;
  }

  .custom-card img {
    width: 200px;
  }
}

この手法の真の強みは、このカードをBootstrapの col-md-3 に配置すれば縦並びに、col-md-12 に配置すれば自動的に横並びになる点です。ユーザーの画面が1024pxなのか2Kなのかを気にする必要はもうありません。

新しい測定単位(cqw, cqh)の活用

コンテナクエリには非常に柔軟な単位セットも用意されています。コンポーネント自体の幅に比例してフォントサイズを調整することなどが可能です:

  • cqw: コンテナの幅の1%。
  • cqh: コンテナの高さの1%。

例えば、タイトルのサイズを常にカードの大きさに合わせるには次のように記述します:

.custom-card h2 {
  font-size: clamp(1rem, 8cqw, 2rem);
}

デバッグとフォールバックのTips

コンテナクエリを扱っていると、ブラウザのサイズを変えてもCSSが即座に反映されず戸惑うことがあります。そんな時は Chrome DevTools を活用しましょう。

要素を検証(Inspect)すると、要素の横に “container” というバッジが表示されます。それをクリックすると、クエリの対象となっているコンテナがハイライトされます。もしCSSが適用されない場合は、直近の親要素に container-type が宣言されているか確認してください。

(IEや古いSafariなどの)古いブラウザをサポートする必要があるプロジェクトでは、@supports を使用します:

@supports not (container-type: inline-size) {
  /* ここにFlexboxやメディアクエリを使用したフォールバック用CSSを記述 */
  .custom-card { flex-direction: column; }
}

すべての要素をコンテナクエリにする必要はありません。再利用性の高いUIコンポーネントに限定して使用するのが良いでしょう。ヘッダーやフッターのようなページ全体のレイアウトには、依然としてメディアクエリが最も最適でシンプルな選択肢です。

Share: