CSS コンテナクエリの基礎知識と便利な使い方を解説

CSSのコンテナクエリが、Chrome Canaryのフラグで利用できるようになりました。正式なサポートはこれからですが、一足先に、コンテナクエリの基礎知識と便利な使い方を紹介します。

メディアクエリはビューポートサイズに基づきますが、コンテナクエリは文字通り親コンテナに基づいてスタイルを定義できます。これによりコンポーネントを複数のコンテクストで使用でき、コンポーネント単位の実装も簡単になります。

CSS コンテナクエリの基礎知識と便利な使い方を解説

Say Hello To CSS Container Queries
by Ahmad Shadeed

下記は各ポイントを意訳したものです。
※当ブログでの翻訳記事は、元サイト様にライセンスを得て翻訳しています。

はじめに

私がフロントエンドのデベロッパーとして過ごした過去6年間で、今ほどCSSの機能に興奮したことはありません。コンテナクエリのプロトタイプが、Chrome Canaryのフラグで利用できるようになりました。Miriam Suzanneをはじめとする関係者皆さまの努力に感謝します。

CSSコンテナクエリのサポートについては、多くのジョークを目にした記憶がありますが、ついに実装されました。この記事では、なぜコンテナクエリが必要なのか、コンテナクエリを使用するとどのように作業が楽になるのか、そして何よりもよりパワフルなコンポーネントやレイアウトを実現できるのかを紹介したいと思います。

私と同じようにワクワクしているなら、さっそく始めましょう。
準備はいいですか?

CSSメディアクエリの問題点

Webページはさまざまなセクションやコンポーネントで構成されていますが、わたし達はそれらをCSSメディアクエリを使用してレスポンシブ化しています。もちろんそれは悪いことではありませんが、メディアクエリには限界があります。

例えば、メディアクエリを使用して、コンポーネントの最小バージョンをスマホとデスクトップの両方に表示することができます。ほとんどの場合、レスポンシブWebデザインはビューポートやスクリーンサイズではありません。コンテナのサイズについてです。下記の例をご覧ください。

カードコンポーネントのレイアウト

カードコンポーネントのレイアウト

カードコンポーネントを使用した典型的なレイアウトがあります。これには2つのバリエーションがあります。

  • 垂直に積み重ねて配置(サイドバー)
  • 水平に並べて配置(メイン)

このレイアウトをCSSで実装する方法はいくつかありますが、最も一般的なのは下記の通りです。ベースとなるコンポーネントを作成してから、そのバリエーションを作成します。

水平バージョンを作成するために.c-article--horizontalを使用したことに注目してください。ビューポートの幅が46remより大きい場合、コンポーネントは水平方向のバリエーションに切り替える必要があります。

この実装は悪いことではありませんが、どういうわけか私は少し制限されているように感じます。コンポーネントがブラウザのビューポートやスクリーンのサイズではなく、親の幅に応じるようにしたいと考えます。

メインにデフォルトの.c-cardを使用したいと考えます。
どうなると思いますか?
カードは親の幅に応じて拡張されるため、大きすぎます。下記をご覧ください。

メインでデフォルトの.c-cardを使用した場合

メインでデフォルトの.c-cardを使用した場合

この問題は、CSSコンテナクエリで解決できます。
2021年になってようやく望む結果を得ることができるようなりました。

コンテナクエリ

親の幅が400pxを超える場合は、水平に切り替えられますか?

直接の親の幅が400pxより大きい場合は、水平に切り替える必要があることをコンポーネントに伝える必要があります。そのため、CSSは下記のようになります。

contain@containerが、コンテナクエリです!

CSSコンテナクエリはどのように役立つのか?

注: CSSコンテナクエリは2021年4月現在、Chrome Canaryのフラグでしかサポートされていません。

CSSコンテナクエリを使用すると、上記の問題を解決し、流動的なコンポーネントを作成できます。つまり、コンポーネントを狭い親に入れれば積み重ねバージョンになり、広い親に入れれば水平バージョンになります。繰り返しになりますが、これらはすべてビューポートの幅には依存しません。

イメージとしてはこんな感じです。

サイトのキャプチャ

左: メディアクエリ、右: コンテナクエリ

パープルの輪郭は親の幅を表しています。親の幅が大きくなると、コンポーネントもそれに応じて変化することに注目してください。

すごいと思いませんか?
これがCSSコンテナクエリの性能です。

CSSコンテナクエリの基礎知識

コンテナクエリを試すには、Chromeのアドレスバーに「chrome://flags」を入力して、「container queries」を検索して、有効にします。

最初のステップは、containプロパティを追加することです。コンポーネントは親の幅に応じて変化するので、ページ全体ではなく、影響を受けるエリアのみを再描画するようにブラウザに伝える必要があります。containプロパティを使用して、そのことを事前にブラウザに知らせることができます。

inline-sizeという値は、親の幅の変更にのみに反応することを意味しています。block-sizeも使用してみましたが、まだ機能しません。私が間違っていたらご指摘ください。

最初のステップは、これだけです。
.o-grid__item要素をその中の.c-articleの包括親として定義しました。

次のステップでは、コンテナクエリを機能させるスタイルを追加します。

この@container.o-grid__item要素で、min-width: 400pxはその幅です。さらに、スタイルを追加することもできます。

これだけの実装でコンテナクエリがどのように機能するかをご覧ください。

デモのアニメーション

コンテナクエリがどのように機能するか

このデモには以下のスタイルがあります。

  1. デフォルトは、サムネイルとテキストが積み重なったカード。
  2. サムネイルが小さい横長のカード。
  3. サムネイルが大きい横長のカード。
  4. 親のサイズがさらに大きい場合は、特集記事であることを示すためにヒーローのようなスタイルになります。

次に、CSSコンテナクエリの使用例を見ていきましょう。

CSSコンテナクエリの使用例

それでは、CSSコンテナクエリの使用例を見てみましょう。

コンテナクエリとCSS Gridのauto-fit

CSS Gridでauto-fitを使用すると、予期しない結果になる場合があります。例えば、コンポーネントの幅が広くなりすぎて、コンテンツが読みにくくなるなどです。

少しコンテクストを与えるために、CSS Gridのauto-fitauto-fillの違いをビジュアルで示します。

auto-fitとauto-fillの違い

上: auto-fill、下: auto-fit

auto-fitの場合、アイテムが拡張されて使用可能なスペースがいっぱいになります。そしてauto-fillの場合はアイテムは拡張せず、代わりに空きスペース(右端の点線のアイテム)ができます。

これがCSSコンテナクエリと関係あるの?と思われるかもしれません。各グリッドアイテムはコンテナであり、それが拡張された時(つまりauto-fitを使用している時)、それに基づいてコンポーネントを変更する必要があります。

4つのアイテムがあり、下記のように表示されます。

auto-fitを使用した場合

auto-fitを使用した場合

アイテムの数が少なくなると、下記のようにアイテムの幅が広くなります。その理由はauto-fitを使用しているからです。アイテムが3つだと見栄えはいいですが、2つ1つと少なくなると幅が広すぎるため、見栄えはよくありません。

アイテムの数が少ない場合

アイテムの数が少なくなると、幅が広くなる

各アイテムが親の幅に応じて変化するとしたらどうなると思いますか? そうすればauto-fitのメリットを十分に得ることができます。必要なことは下記の通りです。

グリッドアイテムの幅が400pxより大きい場合、アイテムを水平スタイルに切り替える必要があります。これを実現するには、次のようにします。

また、グリッド内のアイテムが唯一である場合には、アイテムをヒーローセクションで表示してみます。

コンテナクエリの実装例

親の幅に応じて各アイテムが変化

これで終わりです。
親の幅に反応するコンポーネントができ、どんな状況でも動作するようになりました。これはすごいことだと思いませんか?

See the Pen
Article - QC
by Ahmad Shadeed (@shadeed)
on CodePen.

サイドバーとメイン

<aside>のような幅が狭いコンテナでも機能するように、コンポーネントを調整する必要がある場合がよくあります。

これにぴったりなのが、ニュースレターのセクションです。幅が狭い場合は積み重ね、幅が広い場合には水平方向に広げる必要があります。

ニュースレターのセクション

ニュースレターのセクション

上記のモックアップには、2つの異なるコンテクストが存在します。

  • asideのセクション
  • mainのセクション

コンテナクエリがなければ、CSSでバリエーションクラス(例えば.newsletter--stackedなど)を用意しないと、これは実装できません。

Flexboxで十分なスペースがない場合にアイテムを強制的にラップさせることは承知していますが、それだけでは不十分です。実装にはさらに多くのコントロールが必要です。

  • 特定の要素を非表示にする
  • ボタンを全幅にする

これで下記のように実装されます。

ニュースレターのデモ

ニュースレターのデモ

実際の動作は、下記でご覧ください。

See the Pen
Newsletter - QC
by Ahmad Shadeed (@shadeed)
on CodePen.

ページネーション

ページネーションは、コンテナクエリを使用するのに適しているが分かりました。「前へ」と「次へ」のボタンを用意し、十分なスペースがある場合はそれらを非表示にして、完全なページネーションを実装することができます。

親の幅に応じて、どのように変化するかをご覧ください。

ページネーション

親の幅に応じて変化するページネーション

これを実装するには最初にデフォルトのスタイル(積み重ね)を定義してから、他の2つのスタイルを実装します。

実際の動作は、下記でご覧ください。

See the Pen
Pagination - QC
by Ahmad Shadeed (@shadeed)
on CodePen.

プロフィールのカード

プロフィールのカード

プロフィールのカード

これも複数のコンテクストで使用するのに適した例です。カードが小さな状態では小さなビューポートやサイドバーのようなコンテクストで機能し、大きな状態では2カラムのグリッドに配置するなどより大きなコンテクストで機能します。

これで、単一のメディアクエリを使用せずに、構成要素の言葉が異なるコンテクストでどのように表示されるかを確認できます。

プロフィールのカード

カードはサイドバーとメインで表示が最適化される

実際の動作は、下記でご覧ください。

See the Pen
Profile Card - QC
by Ahmad Shadeed (@shadeed)
on CodePen.

フォーム要素

フォームでの使用例についてはまだ深く考えていませんが、頭に浮かんだのは、ラベルと入力欄を水平に並べるのではなく、積み重ねに切り替えることです。

フォーム要素

上: 親コンテナが大きい場合、下: 親コンテナが小さい場合

実際の動作は、下記でご覧ください。

See the Pen
Form Input - CQ
by Ahmad Shadeed (@shadeed)
on CodePen.

CSSコンテナクエリのデバッグ方法

CSSコンテナクエリが役立つ使用例をいくつか紹介しましたが、コンポーネントをデバッグするにはどうすればよいでしょうか?

ありがたいことに、コンポーネントの親のresizeプロパティを使用して簡単にデバッグすることができます。

コンポーネントのテスト

親要素にresizeプロパティを加える

Bramus Van Dammeによる素晴らしい記事で、このテクニックを知りました。

デベロッパーツールでコンテナクエリをデバッグするのは簡単ですか?

答えは、ノーです。
@container (min-width: value)は表示されません。しかし、サポートされるのは、時間の問題だと思います。

フォールバックを提供することは可能ですか?

はい、特定の方法でフォールバックを提供することが可能です。これを行う方法を説明する2つの素晴らしい記事があります。

まとめ

私はCSSコンテナクエリについて学び、ブラウザで試してみて楽しかったです。まだ正式にはサポートされていませんが、ブラウザで試してみるには絶好の機会です。

フロントエンドのデベロッパーとしてわたし達の仕事の一部は、このような機能の実装に取り組む人々を支援することです。実際にテストしてみることで、その機能が主要なブラウザでサポートされるようになったときの問題は少なくなるでしょう。

終わりに

CSSのデバッグに関する電子書籍を書いていることをお知らせします。

サイトのキャプチャ

興味がある場合は、debuggingcss.comにアクセスして、本に関する最新情報を購読してください。

コメントや提案があれば、@shadeed9までお願いします。

sponsors

top of page

©2021 coliss