CSSの新しい単位がすごく便利!コンテナベースの相対単位「コンテナ単位(qw, qh)」の基礎知識と使い方
Post on:2021年10月7日
CSSでよく使用する単位といえば、px, em, remをはじめ、最近ではvh, vwなどだと思います。特にレスポンシブ対応のレイアウト・コンポーネントを実装する時には、ビューポート相対単位のvh, vwが非常に便利です。
CSSはメディアクエリの登場で進化したように、コンテナクエリの登場でさらに進化しようとしています。新しい単位「コンテナ単位(qh, qw)」は、コンテナのサイズをベースにする相対単位です。
コンテナ単位を使用すると、下記のようにコンテナの幅をベースにした値でfont-sizeを定義したり、同一ページ内で異なる幅のカラム(コンテンツとサイドバー、2カラムと3カラム)に同じコンポーネントやテキストを異なるサイズで配置したり、異なる幅のカラムでスペースの量を変えたりできます。
ビューポート単位では、同一ページだとビューポートの基準値は同じなので、こういうことはできません。
CSS Container Query Units
by Ahmad Shadeed
下記は各ポイントを意訳したものです。
※当ブログでの翻訳記事は、元サイト様にライセンスを得て翻訳しています。
訳者注
単位の名称は仕様の「Container Units」に準じて「コンテナ単位」にしています。
はじめに
先日、CSSのコンテナ単位(Container Units)がサポートされているというMiriam Suzanneのツイートを見かけました。これはもともと、Una KravetsがGithubで提案したものです。私はコンテナ単位を試してみて、CSSコンテナクエリからさらに多くの利益を得ることができるかを考えずにはいられませんでした。
この記事では、コンテナの各単位がどのように機能するのか、それらの単位を使用してコンポーネントが親の幅に対してどのように反応するのかをできるだけ解説したいと思います。
CSSのコンテナクエリをまだ知らない方は、以前の記事をご覧ください。
コンテナクエリは、Chrome Canaryのフラグでのみサポートされています。この機能を使用するには、アドレスバーに「chrome://flags」を入力し、「Enable CSS Container Queries」を検索して、この機能を有効にしてください。
「Enabled」にすると、コンテナクエリが使用できる
ビューポート単位とコンテナ単位の違い
CSSには、目的に応じて使用できる単位がたくさんあります。最もよく使用される単位はpx、rem、emです。コンテナ単位に近いものがあるとすれば、ビューポート単位(vw、vhなど)でしょうか。
CSSのビューポート単位は、ブラウザのビューポート(幅または高さ)に対応するように機能します。それは素晴らしいことですが、常にビューポートサイズに関連した単位を使用したいわけではありません。たとえば、コンテナの幅を指定してクエリを実行したい場合はどうでしょう? そのためにコンテナ単位があります。
分かりやすくするために、ビューポート単位とコンテナ単位の違いをご覧ください。
左: ビューポート単位、右: コンテナ単位
左ではfont-sizeがremとvwで定義されており、これはビューポートの幅に対して相対的になります。場合によってはうまく機能するかもしれませんが、ビューポートサイズに相対するため、予期せぬ問題を引き起こす可能性があります。
コンテナ単位は、コンポーネント内のfont-size、padding、marginなどを処理する際の労力と時間を節約できます。フォントのサイズを手動で増やす代わりに、コンテナ単位を使用できます。
カードのコンポーネント
カードのコンポーネントでは、スタックスタイルから始まり、コンテナが大きくなるとヒーローのようなスタイルになります。このようなコンポーネントでは、以下を変更する必要があるかもしれません。
- サムネイル画像のサイズ
- フォントのサイズ
- 要素間のスペース
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 |
.card { /* The stacked, base style */ } .card__title { font-size: 1rem; } /* The horizontal style, v1 */ @container (min-width: 400px) { .card__title { font-size: 1.15rem; } } /* The horizontal style, v2 */ @container (min-width: 600px) { .card__title { font-size: 1.25rem; } } /* The hero style */ @container (min-width: 800px) { .card__title { font-size: 2rem; } } |
.card__titleのフォントサイズが、各コンテナクエリでどのような値で定義されているかに注目してください。
こういったスタイルの重複(font-sizeの重複)は、CSSのclamp()関数と一緒にコンテナ単位を使用することで、回避できます。
参考: CSSの比較関数が便利すぎる!min(), max(), clamp()の使い方を詳しく解説
1 2 3 |
.card__title { font-size: clamp(1rem, 3qw, 2rem); } |
これで、font-sizeの定義は一度だけで済みます。これを視覚的に比較すると、次のようになります。
左: 今までの単位を使用した場合、右: コンテナ単位を使用した場合
ビューポート単位に慣れていれば、目新しいことではないと思います。ブラウザのビューポートではなく、コンテナに対してクエリを実行するのと同じです。
CSSがすっきりしますよね。
実際の動作は、下記のデモでご覧ください。
See the Pen
Query Units - Intro by Ahmad Shadeed (@shadeed)
on CodePen.
CSSのコンテナ単位とは
CSSのコンテナ単位は、クエリコンテナのサイズを基準にした長さを指定します。この単位を使用したスタイルシートは、コンポーネントをあるクエリコンテナから別のクエリコンテナに簡単に移動できます。
コンテナ単位の利点を理解したところで、どのような単位があるか確認しておきましょう。
CSSの仕様によると、
-
- qw(query width)
- コンテナ幅の1%。例えば、5qwはコンテナ幅の5%です。
-
- qh(query height)
- コンテナ高さの1%。例えば、5qhはコンテナ高さの5%です。
-
- qmin(query minimum)
- クエリ幅qwまたはクエリ高さqhの小さい方の値。
-
- qmax(query maximum)
- クエリ幅qwまたはクエリ高さqhの大きい方の値。
他にもqiとqbという2つの単位があり、それぞれquery inlineとquery blockを意味します。これらは、インラインのサイズとブロックのサイズの1%です。
コンテナ単位の使用例
カードコンポーネントにコンテナ単位を使用する
上記で説明したカードの例に加えて、コンテナの幅に応じてフォントサイズをわずかに大きくしたいスタックカードにも、コンテナ単位を使用できます。
カードコンポーネント
コンテナのサイズに応じて、フォントのサイズがわずかに大きくなっていることに注目してください。これは、ページ上のどこに配置しても機能するカードコンポーネントを実装する際に役立ちます。
実際の動作は、下記のデモでご覧ください。
See the Pen
Query Units - Card by Ahmad Shadeed (@shadeed)
on CodePen.
重要さに応じてfont-sizeを変更する
ある要素が他の要素よりも大きい場合、そのある要素はより重要であることを示している可能性が高いです。その良い例がasideとmainです。aside内の見出しの大きさは、main内の見出しよりも小さくするべきです。
asideとmain内の見出しの大きさが異なる
aside内の見出しがmain内の見出しよりも小さいことに注目してください。これはコンテナ単位のおかけで簡単に実装できます。
まず、asideとmainをinline-sizeのコンテナとして定義する必要があります。
1 2 3 4 |
side, main { container: inline-size; } |
次に、セクションタイトルにコンテナ単位を使用します。また、margin-bottomにもコンテナ単位を使用できます。
1 2 3 4 |
.section-title { font-size: clamp(1.25rem, 3qw, 2rem); margin-bottom: clamp(0.5rem, 1.5qw, 1rem); } |
実際の動作は、下記のデモでご覧ください。
See the Pen
Query Units - Importance by Ahmad Shadeed (@shadeed)
on CodePen.
バイオコンポーネント
バイオコンポーネント
バイオコンポーネントは、小さなコンテナ(サイドバーなど)に配置したり、スマホのビューポートに表示したり、ヘッダのような大きなコンテナに表示することもできます。つまり、コンテナの幅がいろいろな場合です。
コンテナ単位を使用すると、コンテナ幅に応じたコンポーネントを簡単に実装できます。このバイオコンポーネントを例にすると、画像のサイズとフォントのサイズがコンテナの幅に応じて変化します。
1 2 3 4 5 6 7 8 9 10 |
.bio { container: inline-size; } .c-avatar { --size: calc(60px + 10qw); width: var(--size, 100px); height: var(--size, 100px); margin-bottom: clamp(0.5rem, 3qmin, 2rem); } |
実際の動作は、下記のデモでご覧ください。
See the Pen
Query Units - Bio by Ahmad Shadeed (@shadeed)
on CodePen.
カウンター付きの見出し
場合によっては、見出しの横にカウンターを配置することがあります。これは、コンテナ単位の完璧な使用例です。
カウンター付きの見出し
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
.article-body { counter-reset: heading; } h2 { container: inline-size; font-size: clamp(1.25rem, 3qw, 2rem); margin-bottom: clamp(0.5rem, 1.5qw, 1rem); } h2:before { --size: calc(1.25rem + 3qw); content: counter(heading); counter-increment: heading; width: var(--size); height: var(--size); font-size: calc(0.85rem + 1qw); margin-right: calc(var(--size) / 4); } |
実際の動作は、下記のデモでご覧ください。
See the Pen
Query Units - Heading Counter by Ahmad Shadeed (@shadeed)
on CodePen.
要素間のスペースを動的に
ビューポート単位を使用して、CSS Gridで動的な要素間のスペース(ギャップ)を実装したことがあると思います。下記のようなCSSです。
1 2 3 |
.wrapper { gap: calc(1rem + 2vw); } |
では、特定のラッパー内のコンポーネントだとどうでしょうか?
ビューポート単位を使用しても機能しません。この場合には、コンテナ単位を使用するのが適切です。
要素間のスペースを動的に
1 2 3 4 5 |
.card { display: flex; flex-direction: column; gap: calc(0.5rem + 1qmin); } |
広いコンテナでコンポーネントが水平型に切り替わると、スペースが少し大きくなります。
コンテナを定義せずにコンテナ単位を使用するとどうなるか
CSSの仕様によると、対象となるクエリコンテナがない場合は、その軸の小さいビューポートサイズを使用します。
つまり、ブラウザはコンテナ単位をビューポート単位のように処理します。次の例を考えてみましょう。
1 2 3 |
h2 { font-size: clamp(1.25rem, 3qw, 2rem); } |
もし<h2>に定義されているコンテナがない場合、ブラウザは3qwをビューポート幅の3%であるかのように処理します。つまり、コンテナを定義せずにコンテナ単位を使用すると、予想外の結果になる可能性があります。
終わりに
この記事があなたのお役に立てれば幸いです。
コメントや提案があれば、@shadeed9までお願いします。
sponsors