代表的な面接トピック

フロントエンド面接:CSS コンテナクエリはメディアクエリとどう異なるのか?

フロントエンド普通
Offer.cc 編集チーム公開日 更新日

質問

カードコンポーネントがメインカラム、サイドバー、グリッド内に配置されています。CSS コンテナクエリがメディアクエリとどのように異なるかを説明し、カードコンテナの幅に応じてレイアウトを変更する CSS を記述した上で、コンテインメント、スコープ、フォールバック、テストについて説明してください。

プロンプトとコンテキスト

カードコンポーネントがメインカラム、サイドバー、グリッド内に配置されています。CSS コンテナクエリがメディアクエリとどのように異なるかを説明し、カードコンテナの幅に応じてレイアウトを変更する CSS を記述した上で、コンテインメント、スコープ、フォールバック、テストについて説明してください。

メディアクエリはビューポートやデバイスの特性を評価します。一方、コンテナクエリは祖先クエリコンテナのサイズ、スタイル、またはスクロール状態を評価します。GreatFrontEnd の CSS 面接ガイドではコンテナクエリが面接質問として掲載されており、Hack Frontend の HTML/CSS 質問リストでもこのトピックが扱われています。また、MDN では container-type@container、およびコンテナクエリ単位が文書化されています。この質問は特定の企業に限定されたものではありません。

面接官が評価するポイント

面接官は、候補者が CSS を書く前に応答対象を正しく特定できるかを確認します。優れた回答では、container-type: inline-size がサイズクエリコンテキストを確立すること、クエリルールがコンテナ自体ではなく子孫要素にスタイルを適用すること、デフォルトでは最も近い適格な祖先が使用されること、そして同一のビューポート幅であってもカード幅が異なる場合にコンテナクエリが必要になる理由を説明します。

また、サイズコンテインメントの副作用、名前付きコンテナの境界、ブラウザのフォールバック、テストに関する理解もチェックされます。コンテナを確立したりネストを処理したりせずに単に @media@container に置き換えるだけでは、安定して動作しません。

明確化のための質問

  • 何に基づいて応答させる必要がありますか? このプロンプトでは、ビューポート全体ではなくカードのインラインサイズに応答します。
  • スタイルクエリやスクロール状態クエリは必要ですか? いいえ。この回答ではサイズクエリに焦点を当て、その他は拡張機能として扱います。
  • 対象ブラウザのサポート状況はどうなっていますか? まずこれを確認し、利用可能なベースレイアウトとフォールバックを維持します。
  • コンポーネントの境界はネストされる可能性がありますか? その場合、container-name を使用して意図した境界を明示します。

30秒の回答

「メディアクエリはビューポートを監視し、ページレベルのブレークポイントに適しています。コンテナクエリはコンポーネントの祖先を監視し、さまざまなスロットに配置される再利用可能なコンポーネントに適しています。カードリストに container-type: inline-size を設定し、@container を使用してインラインサイズの閾値でカードのレイアウトを切り替えます。クエリは子孫要素にスタイルを適用し、デフォルトでは最も近い適格なコンテナを使用します。複雑なネストには container-name を使用します。ベーススタイルと @supports フォールバックを用意した上で、ビューポートを固定したままメインカラム、サイドバー、グリッド、および非対応ブラウザで親要素のサイズを変更してテストします。」

ステップ・バイ・ステップの回答

ステップ 1: 応答対象とスコープを比較する

項目メディアクエリコンテナクエリ
応答対象ビューポート、デバイス、またはユーザー設定祖先クエリコンテナのサイズ、スタイル、またはスクロール状態
一般的なスコープページレベルのレイアウト再利用可能コンポーネントの内部レイアウト
設定@media がメディア特性を直接読み取る祖先が container-type を設定し、子孫が @container を使用する
コンポーネントの挙動各インスタンスがビューポートのブレークポイントを共有することが多い各インスタンスが自身に割り当てられた幅に応答する

メディアクエリは、ナビゲーション、ページのカラム構成、印刷、ユーザー設定に直接適しています。コンテナクエリは、コンポーネントが自身の配置スロットの幅を把握できないケースを解決します。たとえば、同じビューポート幅であってもメインカラムとサイドバーで異なるレイアウトを使用できます。

ステップ 2: サイズクエリコンテキストを確立する

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

.card {
  display: grid;
  gap: 0.75rem;
}

@container card-list (inline-size > 40rem) {
  .card {
    grid-template-columns: 8rem 1fr;
    align-items: center;
  }
}

inline-size はインライン軸のサイズクエリコンテナを確立し、書字方向(writing mode)が重要になる場合にもうまく機能します。size はより強力な2軸のコンテインメントを確立するため、ブロック軸のクエリが必要な場合にのみ選択すべきです。normal はサイズクエリコンテキストを確立しません。条件は @container で記述され、一致したルールは子孫要素に適用されます。

ステップ 3: 最も近いコンテナ、名前、単位を理解する

名前がない場合、ブラウザは最も近い適格な祖先を見つけます。そのため、ネストされたコンポーネントが誤った境界を読み取る可能性があります。名前を付けることで意図が明示的になります。@container card-list (...) は、card-list という名前のコンテナにのみ一致します。cqwcqi などのコンテナクエリ長単位は、クエリコンテナの幅またはインラインサイズに基づいてスケールしますが、極端に小さなコンテナで文字が読めなくならないよう、適切な最小値・最大値と組み合わせる必要があります。

クエリの結果によってコンテナ自身のサイズが変化してはならず、そうならないとフィードバックループ(無限ループ)が発生する可能性があります。コンテインメントとスコープのルールはこのループを防ぎます。また、サイズコンテインメントによって自動サイズ計算(automatic sizing)が変化することがあるため、空のコンテンツ、未読み込みの画像、コンテンツ依存の高さなどを確認してください。

ステップ 4: フォールバックとプログレッシブエンハンスメントを設計する

css
.card {
  display: block;
}

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

  @container (inline-size > 40rem) {
    .card {
      display: grid;
      grid-template-columns: 8rem 1fr;
    }
  }
}

ベースレイアウトはコンテナクエリがなくても可読性を保つ必要があります。メディアクエリによってページレベルのフォールバックを提供することはできますが、ビューポートのブレークポイントではサイドバーやグリッドセルのあらゆる幅を正確に表現できません。対象ブラウザに必要な機能がサポートされていない場合は、コアコンテンツやインタラクションを損なうことなくベーススタイルを維持するようにします。

ステップ 5: シナリオと境界をテストする

ブラウザのビューポートを固定した状態にします。同じコンポーネントをメインカラム、サイドバー、2カラムグリッドに配置し、親要素の幅のみを変更して、カードがビューポートではなくコンテナに応答することを確認します。ネストされた名前付きコンテナ、異なる書字方向、読み込み前後の画像、極端に狭いコンテナ、動的スロット、およびコンテナクエリ非対応ブラウザをテストします。また、コンポーネントの再利用時に誤ったコンテナが暗黙的に選択されないよう、単一ページの DOM の深さに依存していないかも検証します。

許容される実装の境界

回答ですべてのクエリタイプを網羅する必要はありませんが、ビューポートと祖先コンテナを正確に区別し、実際のクエリコンテキストを用いて動作可能なコード例を示す必要があります。もし候補者が size、スタイルクエリ、またはスクロール状態クエリを選択した場合は、追加のコンテインメント効果、対象ブラウザ、テスト境界について説明する必要があります。サポート状況が不確かな場合は、ベースレイアウトを安全なデフォルトとすべきです。

よくある間違いと反面教師

  • container-type の指定忘れ: クエリコンテキストがない @container はサイズに応答しません。
  • コンテナ自身をクエリの対象にする: 安定したクエリは子孫要素にスタイルを適用します。クエリ結果によって自身をサイズ変更するとループが発生する可能性があります。
  • デフォルトで size を使用する: 2軸のコンテインメントは自動サイズ計算に影響を与える可能性があります。水平方向のみが必要な場合は inline-size を選択してください。
  • 幅の広い画面でのみテストする: 単一のビューポート幅でもサイドバーとメインカラムの幅は異なるため、ビューポートを固定した状態で親要素のサイズを変更してテストします。
  • ベースフォールバックの省略: 非対応ブラウザでは、拡張機能が適用される前に利用可能なベースレイアウトが必要です。

フォローアップ質問と回答

どのような場合に今でもメディアクエリを使用しますか?

ナビゲーション、ページのカラムレイアウト、印刷用レイアウト、またはユーザー設定がビューポートやメディア特性に依存する場合にメディアクエリを使用します。コンポーネント内部のブレークポイントがその親要素に依存する場合は、コンテナクエリを使用します。

inline-sizesize はどのように選びますか?

コンポーネントが利用可能な水平スペースのみに応答する場合は inline-size を選択します。ブロック軸とインライン軸の両方が必要な場合は size を検討し、自動サイズ計算、空コンテンツ、画像読み込み後の動作を検証します。

非対応ブラウザにはどのように対処しますか?

基本となるシングルカラムまたは流動的レイアウトを提供し、@supports (container-type: inline-size) を使用して段階的に拡張します。メディアクエリはページレベルの動作を補完できますが、コンテナレベルのあらゆるブレークポイントを代替することはできません。

公開情報ソース

関連する質問