CSSコンテナクエリの登場で、デザインのやり方も考え方も大きく変わる
Post on:2021年6月10日
現在のレスポンシブデザインは、ビューポートにもとづいてレイアウトを最適化します。そして、コンテナクエリは親要素のコンテナにもとづいてレイアウトを最適化します。コンテナクエリとは何か、デザイナーのワークフローにどのような変化をもたらすかを紹介します。
今まではビューポート(メディアクエリ)で変化するコンポーネントと影響を受けないコンポーネントの2種類でしたが、これからは親コンテナ(コンテナクエリ)で変化するコンポーネントも必要になります。
CSS Container Queries For Designers
by Ahmad Shadeed
下記は各ポイントを意訳したものです。
※当ブログでの翻訳記事は、元サイト様にライセンスを得て翻訳しています。
- はじめに
- レスポンシブデザインの現状
- コンテナクエリとは
- コンテナクエリを念頭に置いたデザイン
- デベロッパーとのコミュニケーション方法
- レスポンシブ コンポーネントをデザインする際の複雑さを回避
- CSSのコンテナクエリの使用例
- 終わりに
はじめに
Webデザインでは、さまざまなスクリーンサイズに合わせてデザインする必要があります。それらのデザインをもとに、デベロッパーはCSSのメディアクエリを使用してビューポートの幅や高さに応じて、デザインを変更して実装します。これまで過去10年間にわたり、わたし達はこのようにしてWebレイアウトをデザインしてきましたが、これからはさらに良くなろうとしています。そんなあなたに朗報があります!
デベロッパーが長い間要望していたCSSのコンテナクエリが実装され、Chrome Canaryで実験的な機能として利用できるようになりました。
この記事では、コンテナクエリとは何か、デザイナーのワークフローにどのような変化をもたらすか、などについて解説します。この記事の主な目的は、次のステップに備えるコンセプトを理解することなので、あなたがコードを理解できるデザイナーであろうとなかろうと支障はありません。もし理解できないCSSがあったとしても、無視して読み進めてください。
前置きは以上です、さぁ始めましょう!
訳者注:
コンテナクエリについて詳しく知りたい場合は、先日の記事もご覧ください。
レスポンシブデザインの現状
現状のデザインは、レイアウトを複数のバリエーション用意し、ビューポートの幅に応じて内部のコンポーネントがどのように変化するかを示していると思います。それらを元に、スマホ・タブレット・デスクトップといった異なるスクリーンサイズのデザインをしています。
現状はレイアウトを複数のバージョンを用意している
上記は、デザイナーが同じデザインの3つのバリエーションを作成しているので、デベロッパーはどのように動作するのかを把握することができます。
ここまでに問題点はありません。
デザインとそのバリエーションのより詳細な外観を見てましょう。ここで、CSSのコンテナクエリが解決してくれる既存の問題点が明らかになります。
デザインとそのバリエーションのより詳細な外観
Default, Card, Featuredの3つは同じコンポーネントで、3つのバリエーションがあります。デザイナーはこれを伝えるためにレイアウトの複数のバージョンを用意しました。「このコンポーネントはスマホではDefaultで、タブレットではCardのような外観です」と言っているのと同じことです。
デベロッパーはCSSで、このコンポーネントの3つのバリエーションを実装する必要があり、それぞれが固有のレイアウトになっています。
基本的なCSSを見てましょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
.c-media { /* the default styles */ display: flex; flex-wrap: wrap; gap: 1rem; } @media (min-with: 400px) { .c-media--card { display: block; } .c-media--card img { margin-bottom: 1rem; } } @media (min-with: 1300px) { .c-media--featured { position: relative; /* other styles */ } .c-media--featured .c-media__content { position: absolute; left: 0; top: 0; width: 100%; height: 100%; } } |
このCSSでは、メディアクエリまたはビューポートの幅に依存して実装されています。つまり、親の幅に基づいてレイアウトをコントロールすることはできません。
これの何が問題なのかと思われるかもしれません。いい質問ですね。
問題となるのは、デベロッパーがビューポートの幅が特定の値よりも大きい場合にのみ、コンポーネントのバリエーションを使用することに縛られていることです。例えば、Featuredのバリエーションをタブレットサイズで使用したいと思っても、うまくいきません。なぜかと言うと、このコンポーネントのメディアクエリはビューポート幅が1300px以上で有効になるからです。
1300px以上で定義しているので、1024pxでは機能しない
それだけではなく、コンテンツが予想より小さい場合にも問題に直面する可能性があります。この記事コンポーネントを3つ掲載することを前提にデザインされているのに、コンテンツ作成者が1つの記事しか掲載しないこともあります。そのような場合には、空白スペースができてしまうか、記事が空白スペースを埋めるために広がってしまうかのどちらかになります。
記事コンポーネントを3つ掲載することを前提にデザインされている
Case 1では記事の幅が広すぎるため、使用している画像が壊れます。Case 2では使用可能なスペースを埋めるために拡大しているグリッドアイテムが増えてしまいます。これはよろしくありません。
コンテナクエリを使用すれば、親コンテナのサイズに基づいてコンポーネントのレイアウトを決めることができるので、こういった問題は解決できます。
コンテナクエリを使用すると、下記のように問題を解決できます。
コンテナクエリを使用して、問題を解決
それでは、考えをコンポーネントの親に移したらどうなるでしょうか? つまり、親にクエリを実行し、親の幅または高さに基づいてコンポーネントの外観を決定するとどうなるでしょうか?
コンテナクエリのコンセプトについて解説します。
コンテナクエリとは
まずは、コンテナの定義を簡単に説明します。コンテナとは他の要素(複数可)を含む要素で、ラッパーと呼ばれることもあります。コンテナについて詳しく学びたい人は下記の記事をご覧ください。
コンテナクエリのプロトタイプが、Chrome Canaryのフラグで使用できるようになりました。Miriam Suzanneをはじめとする多くの人々の努力に感謝します。
コンポーネントがアイテムの中に配置されると、そのアイテムに含まれることになります。つまり、その親の幅をクエリして、それに基づいて変更することができます。
イエロー: コンテナ
各カードには、各コンポーネントの親を示すイエローのアウトラインがあることに注目してください。CSSのコンテナクエリを使用すると、親の幅に応じてコンポーネントを変更することができます。より分かりやすくするために、上記のHTMLマークアップを下記に示します。
1 2 3 4 5 6 |
<div class="o-grid"> <div class="o-grid__item"> <article class="c-media"></article> </div> <!-- + more items --> </div> |
コンポーネントは.c-mediaのアイテムで、その親は.o-gird_item要素です。CSSは下記の通りです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
.o-grid__item { contain: layout inline-size style; } .c-media { /* Default style */ } @container (min-width: 320px) { .c-media { /* The styles */ } } @container (min-width: 450px) { .c-media { /* The styles */ } } |
最初に、.o-grid__itemという要素がコンテナであることをブラウザに伝えます。そして、親の幅が320px以上の場合は、別のスタイルで表示するようにブラウザに伝えます。450pxのクエリについても同様です。
以上がCSSのコンテナクエリの仕組みです。このCSSは好きな場所で定義できるので、必要に応じてトップレベルのコンテナにクエリを実行することもできます。
CSSのコンテナクエリの基本的な考え方を理解していただいたところで、下記のモックアップをご覧ください。
左: メディアクエリ、右: コンテナクエリ
左のメディアクエリは、ビューポートのサイズに応じてスタイルが変更されます。右のコンテナクエリは、親のサイズに応じてスタイルが変更されるコンポーネントです。このことがコンテナクエリがどれほど強力で便利であるかということです。
コンテナクエリを念頭に置いたデザイン
デザイナーは、この革新的なCSSの機能に対応する必要があります。コンテナクエリにより、CSSの設計・記述方法が大きく変わります。スクリーンサイズに合わせてデザインするだけでなく、コンテナの幅が変化したときにコンポーネントがどのように適応されるべきかを考慮する必要があります。
現在、デザインシステムはますます一般的になっています。デザインチームがルールやコンポーネントを構築し、他のメンバーがそれに基づいてページを構築するというものです。CSSコンテナクエリが登場したことで、コンポーネントが親の幅に応じてどのように適応するかも設計することになります。
下記のデザインをご覧ください。
Webページのモックアップ
ヘッダー、記事セクション、引用文、ニュースレターがあります。それぞれの要素はビューポートの幅または親の幅のどちらかに合わせる必要があります。
コンポーネントを以下のカテゴリに分けます。
- ビューポート(メディアクエリ)で変化するコンポーネント
- 親コンテナ(コンテナクエリ)で変化するコンポーネント
- 汎用: ボタン、タグ、パラグラフなど、影響を受けないコンポーネント。
上記のUIでは、以下のようにコンポーネントを分けることができます。
上から、ビューポートで変化、親コンテナで変化、汎用
このような考え方でUIをデザインすると、親の幅に応じてコンポーネントのバリエーションを考えられるようになります。それを見ていきましょう。
下記は、記事コンポーネントの各バリエーションが特定の幅でどのように表示されるかの一覧です。
記事コンポーネントの各バリエーション
デザイナーとしては、親の幅で考えるのは最初はちょっと奇妙に思えるかもしれませんが、これからはそういう時代になっていきます。フロントエンドのデベロッパーに各コンポーネントの詳細やバリエーションを提供し、彼らに使用してもらうのです。
それだけでなく、特定のコンテキストでのみ表示されるべきコンポーネントのバリエーションを用意することもあります。例えば、イベント一覧のページです。そのような場合には、このバリエーションをどこで使用するかを明確にすることが重要です。
問題は、デザイナーがこれらのコンポーネントをどこで使うべきかを、どうやって伝えるかです。
デベロッパーとのコミュニケーション方法
プロジェクトを成功させるためには、良好なコミュニケーションが重要な要素となります。デザイナーは、コンポーネントのバリエーションがどこで使用されるべきかのガイダンスを提供することが期待されます。それは全ページにわたるデザインであっても、各コンポーネントがどのように使用できるかを示すシンプルな図であっても構いません。
前述の記事コンポーネントで解説します。
コンポーネントのバリエーションがどこで使用されるべきかのガイダンス
各バリエーションを、ビューポートではなく特定のコンテキストにマッピングしていることに注目してください。さらにそれを証明するために、このコンポーネントをCSS Gridで使用した場合にどのように異なる動作をするかをお見せしたいと思います。
CSS Gridでは、auto-fitキーワードを使用して、列の数が想定よりも少ない場合に列を拡張することをブラウザに伝えることができます。この機能は、同じコンテキストで異なるバリエーションを表示するのに役立ちます。
auto-fitの使用方法は下記をご覧ください。
親コンテナによって変化するコンポーネント
親の幅に反応するコンポーネントがあると、とても便利です。前述のように、わたし達はデスクトップサイズでページを表示していて、さまざまなセクションがあり、それぞれの列数も異なります。
レスポンシブ コンポーネントをデザインする際の複雑さを回避
コンポーネントの内部パーツは、LEGOのようなものだと心得ておきましょう。現在のバリエーションに基づいて順番に並べることはできますが、すべてのものには限界があります。フロントエンドのデベロッパーは、コンテナクエリでバリエーションを作成するよりも、全く新しいコンポーネントに取り組んだ方が良い場合もあります。
カードのコンポーネント
このカードのコンポーネントには、以下の内部パーツがあります。
- アバター画像
- 名前
- ボタン
- キーと値のペア
内部パーツが同じままか、少なくとも新しいパーツが含まれない場合は、コンポーネントを変更して次のようなバリエーションを作成できます。
コンポーネントのバリエーション
CSSのコンテナクエリの使用例
CSSのコンテナクエリを使用して実装できる使用例をいくつか見てみましょう。
チャットリスト
このUIコンポーネントは、Facebookのメッセンジャーで見たものです。チャットリストは、ビューポートの幅に応じて変化します。これをコンテナクエリを使用して実装することができます。
チャットリスト
十分なスペースがあれば、リストは横に広がり、サイドバーの各ユーザーの名前が表示されます。チャットリストの親は、動的にサイズが変更される要素とすることができます(例: CSSのビューポート単位やCSSの比較関数を使用するなど)。
CSSでこのUIを実装する方法を紹介します。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
<div class="content"> <aside> <ul> <li> <img src="shadeed.jpg" alt="Ahmad Shadeed" /> <span class="name">Ahmad Shadeed</span> </li> </ul> </aside> <main> <h2>Main content</h2> </main> </div> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
.content { display: grid; grid-template-columns: 0.4fr 1fr; } aside { contain: layout inline-size style; } @container (min-width: 180px) { .name { display: block; } } |
サイドバーの幅は0.4rfなので、動的な幅になっていることに注目してください。サイドバーのasideにcontainプロパティを追加し、コンテナの幅が180pxより大きい場合はユーザー名(.name)が表示されます。
似た使用例として、サイドバーのナビゲーションがあります。アイテムのラベルを積み重ねて表示するか、アイコンの横に表示するかを切り替えることができます。
ラベルの表示位置は親コンテナの幅で変化する
親コンテナの幅が小さい場合は改行され、幅が広い場合はアイコンの横に表示されることに注目してください。
アコーディオン
アコーディオンのパターンは、FAQなどに使用できます。場合によっては、FAQのリストをサイドバーやUIの小さなエリアに追加する必要があるかもしれません。そんな時はコンテナクエリが役に立ちます。
アコーディオン
コンテナクエリを使用してこのUIを実装する方法は下記の通りです。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
@container (min-width: 180px) { .faq-title { display: flex; justify-content: space-between; font-size: 1.25rem; } .faq__icon { width: 60px; height: 60px; background-color: #4f96e7; } } |
検索フィールド
検索フィールド
これは、ページ内の複数の場所に使用されるユニバーサル検索入力がある場合に、非常に便利です。例えば、サイドバー(左)のような小さな場所でもヒーローセクション(右)のような大きな場所でも使用することができます。
イベント一覧
イベント一覧
個人的には、コンテナクエリのこの使用例が気に入っています。同じコンポーネントを複数のコンテクストで使用することができます。上のモックアップではシンプル・ミディアム・ラージの3種類があります。これらをどのように使用するのかを示します。
バリエーションの使用方法
繰り返しになりますが、これは親の幅に適応する同じコンポーネントです。これはすごいことだと思いませんか? 私にとってはそうです。
著者のプロフィール
著者のプロフィール
プロフィールは、ブログでは一般的なコンポーネントです。複数のコンテクストで使用されることがあるため、適応しなければなりません。上記はそれを示しています。
ソーシャルメディアのシェアボタン
ソーシャルメディアのシェアボタン
ソーシャルメディアのコンポーネントを実装する際には、ビューポートが大きくても親が小さい場合(サイドバーなど)にも動作するバージョンを作成する必要がありました。コンテナクエリを使用すると、親の幅に適応させることで簡単に解決できます。
コンポーネントがサイドバーで使用される場合(左)は、小さいバージョンで表示されます。親の幅が大きい場合(右)は、フルバージョンで表示されます。サイドバー用とコンテンツ用の2つを実装する必要はありません。
終わりに
コメントや提案があれば、@shadeed9までお願いします。
sponsors