FlexboxとCSS Gridの使い分け方、よく見かけるUIコンポーネントをFlexboxとGridで実装するテクニックのまとめ
Post on:2020年6月25日
FlexboxとCSS Gridのどちらを使った方がよいか悩んだことはありませんか?
FlexboxとCSS Gridの使い分け方、それぞれの違い、Flexboxの実装例、CSS Gridの実装例、FlexboxとCSS Gridを組み合わせた実装例、フォールバックと古いブラウザのサポート方法を解説します。
Grid for layout, Flexbox for components
by Ahmad Shadeed
下記は各ポイントを意訳したものです。
※当ブログでの翻訳記事は、元サイト様にライセンスを得て翻訳しています。
- はじめに
- CSS GridとFlexboxの違い
- CSS GridとFlexboxの使い分け方
- CSS Gridの実装例
- Flexboxの実装例
- CSS GridとFlexboxを組み合わせて使用する
- フォールバックと古いブラウザのサポート
- CSS GridまたはFlexboxを不適切に使用している場合
- 終わりに
はじめに
私の弟はコンピューターエンジニアリングの新卒で、現在はフロントエンド開発のインターンシップを終えています。彼はCSS GridとFlexboxの両方を学びましたが、Webでよく見かける疑問に気がつきました。
CSS GridとFlexboxのどちらを使用すればよいか決められない時があります。
例えば、CSS Gridでヘッダをレイアウトし、grid-columnでデザインのようになるまで微調整する作業がスムーズではなかったと言っていました。
どちらを使用するかは、CSS GridとFlexboxのコンセプトや実例の前に、主な違いを理解しておく必要があります。CSS Gridは多次元のレイアウトモジュールで、列と行があります。Flexboxは子アイテムを列または行としてレイアウトできますが、列と行の両方をレイアウトすることはできません。
CSS GridとFlexboxの違いがよく分からない人は、ビジュアルで解説したLearn box Alignmentを読むことをお勧めします。
参考: CSS Flexbox の基礎知識と使い方をやさしく解説
参考: 5分で完璧に分かる!CSS Gridの基本的な使い方を解説
それでは、CSS GridとFlexbox、それぞれをいつ使用するのか、そしてその理由について詳しく解説します。
CSS GridとFlexboxの違い
はっきりさせておきますが、CSS GridとFlexboxのどちらを使用するか直接的に決める方法はありません。それに加えて、正しい方法や間違った方法もありません。この記事では、特定の使用例でそのテクニックを使用することを推奨するガイドのようなものです。一般的なコンセプトから説明し、実例を提示します。
1 2 3 4 5 6 7 8 9 10 11 |
/* Flexboxのラッパー */ .wrapper { display: flex; } /* Gridのラッパー */ .wrapper { display: grid; grid-template-columns: 2fr 1fr; grid-gap: 16px; } |
Flexboxは一方向のレイアウト、CSS Gridは多次元のレイアウト
何か気づきましたか?
Flexboxは要素のインラインリストをレイアウトしていますが、CSS Gridは列と行のグリッドを作成しています。Flexboxは横一行に並んで整列しており、必要に応じて縦一列にすることもできます。
1 2 3 4 5 |
/* Flexboxのラッパー */ .wrapper { display: flex; flex-direction: column; } |
Flexboxは一方向のレイアウト、CSS Gridは多次元のレイアウト
CSS GridとFlexboxの使い分け方
CSS GridとFlexboxのどちらを使用するか決めるのは、CSSに慣れていない人にとっては少し難しいかもしれません。ここでは、どちらにするか決める際に私が自問自答する質問を紹介します。
- コンポーネントの子アイテムをどのように表示するか?
インラインにするか、列と行にするか? - コンポーネントはさまざまなスクリーンサイズでどのように機能することが期待されるか?
コンポーネントのすべての子アイテムをインラインで表示する場合は、Flexboxが最適解です。例えば、下記の例をご覧ください。
すべての子アイテムをインラインで表示
子アイテムを列と行に配置する場合は、CSS Gridが最適解となります。
子アイテムをが列と行に配置
これでCSS GridとFlexboxの主な違いを理解できたと思いますので、より具体的な例に進み、決定方法を解説します。
CSS Gridの実装例
では、CSS GridとFlexboxの異なる実装例について見てみましょう。
まずは、CSS Gridについて詳しく説明します。
メインとサイドバー
メインとサイドバーを実装する場合、CSS Gridは最適解です。下記のモックアップをご覧ください。
メインとサイドバー
HTMLとCSSは下記の通りです。
1 2 3 4 |
<div class="wrapper"> <aside>Sidebar</aside> <main>Main</main> </div> |
1 2 3 4 5 6 7 8 9 10 11 |
@media (min-width: 800px) { .wrapper { display: grid; grid-template-columns: 200px 1fr; grid-gap: 16px; } aside { align-self: start; } } |
<aside>要素にalign-selfが使用されなかった場合は、コンテンツの長さに関係なく、サイドバーの高さはメインと同じになります。
カードのグリッド
前述した通り、CSS Gridはその名の通り、グリッドのレイアウトに使用することは完璧な使用方法です。
カードのグリッド
このグリッドのCSSは下記の通りです。
1 2 3 4 5 |
.wrapper { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); grid-gap: 16px; } |
カラム幅を200px以上にし、スペースが足りない場合はカードを新しい行に折り返します。ビューポートの幅が200px未満の場合は、水平スクロールが表示される可能性があるので注意が必要です。
解決策は、ビューポートの幅が十分な場合にのみグリッドの定義をすることです。
1 2 3 4 5 6 7 |
@media (min-width: 800px) { .wrapper { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); grid-gap: 16px; } } |
セクションのレイアウト
下記のモックアップでは、CSS Gridを2つ使用しています。1つ目は2つのエリア(サイドバーとフォーム)を分割し、2つ目はフォームのグリッドです。
セクションのレイアウト
CSS Gridはこういったレイアウトを構築するのに、最適です。CSSは、下記の通りです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
@media (min-width: 800px) { .wrapper { display: grid; grid-template-columns: 200px 1fr; } .form-wrapper { display: grid; grid-template-columns: 1fr 1fr; grid-gap: 16px; } .form-message, .form-button { grid-column: 1 / 3; /* let them take the full width */ } } |
この例は、CSS Gridでフォームのレイアウトの構築についての記事から借りたものです。一読することをお勧めします。
Flexboxの実装例
続いて、Flexboxについて詳しく説明します。
ヘッダ
Webサイトのヘッダは9割方、Flexboxで実装されていると思います。最も一般的なパターンは、左側にロゴ、右側にナビゲーションのアイテムがあります。このパターンはFlexboxに最適です。
ヘッダ
CSSは下記の通りです。
1 2 3 4 5 |
.site-header { display: flex; flex-wrap: wrap; justify-content: space-between; } |
このコンセプトは、下記のデザインでも機能します。
スペースが2つ必要なヘッダ
構造に少し変化がありますが、アイテム間のスペースはjustify-contentプロパティが効いています。
アクションのリスト
リストと聞くと、真っ先に思い浮かべるのは縦のリストかもしれません。しかし、リストはインラインで横に表示される可能性もあります。
アクションのリストの例としては、FacebookやTwitterなどでも見かけます。ユーザーが実行できるアクションボタンを横に表示したリストです。
アクションのリスト
各アイテムは横に並べて配置されており、実装にはFlexboxが最適です。Flexboxの主要な用途の1つと言えるでしょう。
1 2 3 4 5 6 7 |
.actions-list { display: flex; } .actions-list__item { flex: 1; /* アイテムを展開して、アイテム間の利用可能なスペースを均等にする */ } |
これのもう一つのバリエーションとして、モーダルのアクションボタンやヘッダがあります。
モーダルのアクションボタンやヘッダ
モーダルのヘッダとフッタの両方にインラインで表示される子要素があり、子要素の間にはスペースがあります。
ヘッダのCSSは、下記の通りです。
1 2 3 4 |
.modal-header { display: flex; justify-content: space-between; } |
フッタのCSSは、少し異なります。Cancelボタンに自動マージンを定義して、自身を右に押し出すようにします。
参考: CSSのプロパティ値「auto」を使ったテクニックのまとめ、マージンやサイズや配置やFlexboxなど
1 2 3 |
.cancel__action { margin-left: auto; } |
※.cancel_actionという命名は完璧ではないですが、この記事では命名規則にこだわるのは避けたいと思います。
フォームの要素
フォームの入力欄とその隣のボタンの組み合わせは、Flexboxの完璧な使用例です。
フォームの入力欄とボタン
上のフォームでは、入力欄が残りのスペースすべてを占めているので、動的な幅になります。下のフォーム(Facebookのメッセンジャー)も同様で、テキストの入力欄は残りのスペースすべてを占めています。もう少し詳しく見てみましょう。
残りのスペースすべてを占める入力欄
1 |
.input { flex: 1 1 auto; } |
入力欄にflex: 1 1 auto;を使用しないと、残りのスペースが拡大されずに占められないことに注意してください。
コメントスレッド
Flexboxのもう1つの一般的な使用例は、コメントスレッドです。
コメントスレッド
コメントスレッドには、ユーザーの画像とコメントがあります。コメントは親要素から残りのスペースを取得しています。これはFlexboxに適した使用例ですね。
カードのコンポーネント
カードのコンポーネントには多くのバリエーションがありますが、一般的なのは下記のモックアップのようなデザインです。
カードのコンポーネント
左のカードは、Flexコンテナがcolumnになっているため、カードの子アイテムが積み重なって配置されています。右のカードはその逆のrowで横並びになります。flex-directionのデフォルト値は、rowです。
参考: flexコンテナ: flex-direction(横並びと縦並び)
1 2 3 4 5 6 7 8 9 10 |
.card { display: flex; flex-direction: column; } @media (min-width: 800px) { .card { flex-direction: row; } } |
カードで別の一般的なバリエーションは、ラベル付きのアイコンです。ボタンだったり、単に装飾だったりします。
ラベル付きのアイコンのカード
アイコンとラベルのテキストが、水平・垂直方向の中央に配置されていることに注目してください。Flexboxでこれは簡単に実装できます。
1 2 3 4 5 |
.card { display: flex; flex-direction: column; align-items: center; } |
横並びにするにはインラインスタイルはデフォルトのままで、flex-direction: column;を削除してデフォルト値(row)のままにします。
タブ・ボタンメニュー
スクリーンの全幅や、利用可能なスペースすべてを占めるべきアイテムがある場合は、Flexboxが最適です。
タブ・ボタンメニュー
このモックアップでは、各アイテムが利用可能なスペースすべてを占め、幅は同じです。ラッパーのdisplayをflexに定義すると、簡単に実装できます。
1 2 3 |
.tabs__item { flex-grow: 1; } |
このテクニックはReact Nativeでスマホアプリ用のタブバーを構築するために使用されています。React Nativeで上記と同じものを実装するコードは下記の通りです。
1 2 3 4 5 6 7 8 9 10 11 12 |
import React from 'react'; import { View } from 'react-native'; export default FlexDirectionBasics = () => { return ( <View style=> <View style= /> <View style= /> <View style= /> </View> ); }; |
フィーチャーリスト
Flexboxで私が最も気に入っているのは、要素の配置を逆向きにできることです。Flexboxでデフォルトの方向はrowですが、row-reverseで逆向きにできます。
参考: flexコンテナ: flex-direction(横並びと縦並び)
1 2 3 |
.item { flex-direction: row-reverse; } |
例えば、偶数番目のアイテムを逆向きに配置する時にこのテクニックは便利です。
偶数番目のアイテムを逆向きに配置
コンテンツの中央揃え
ヒーローセクションがあり、コンテンツを水平・垂直方向の中央に配置する必要があるとします。水平方向の中央揃えはtext-alignでできるので簡単かもしれません。
コンテンツの中央揃え
1 2 3 |
.hero { text-align: center; } |
では垂直方向の中央揃えは、どうすればよいでしょうか?
その答えは、簡単です。
1 2 3 4 5 6 7 |
.hero { display: flex; flex-direction: column; align-items: center; /* 水平方向の中央揃え */ justify-content: center; /* 垂直方向の中央揃え */ text-align: center; } |
CSS GridとFlexboxを組み合わせて使用する
CSS GridとFlexboxの各レイアウトモジュールにはそれぞれに適した使用例があるだけでなく、両方を使用することもできます。
例えば、カードのリストです。カードのレイアウトにはCSS Gridを使用し、カードのコンポーネントにはFlexboxを使用します。
レイアウトにはCSS Grid、コンポーネントにはFlexbox
レイアウトの要件は、下記の通りです。
- 各行のカードの高さは同じ。
- 「Read more」はカードの高さに関係なく、カードの最後に配置。
- グリッドにはminmax()関数を使用。
参考: minmax()を使うとMedia Queries無しでレスポンシブが簡単に実装できる
1 2 3 4 5 6 7 8 9 10 |
<div class="wrapper"> <article class="card"> <img src="sunrise.jpg" alt=""> <div class="card__content"> <h2><!-- Title --></h2> <p><!-- Desc --></p> <p class="card_link"><a href="#">Read more</a></p> </div> </article> </div> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
@media (min-width: 500px) { .wrapper { display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); grid-gap: 16px; } } .card { display: flex; /* [1] */ flex-direction: column; /* [2] */ } .card__content { flex-grow: 1; /* [3] */ display: flex; /* [4] */ flex-direction: column; } .card__link { margin-top: auto; /* [5] */ } |
上記のCSSについて説明します。
- カードをFlexboxのラッパーとして作成します。
- 方向はcolumnです。つまり、カード要素が積み重ねられます。
- カードコンテンツを拡張して、残りのスペースを占めます。
- Flexboxのラッパーとしてカードコンテンツを作成します。
- 最後に、margin-top: auto;でリンクを押し下げます。これにより、カードの高さに関係なく、「Read more」はカードの最後に配置されます。
このようにCSS GridとFlexboxを組み合わせることは難しくなく、レイアウトを実装する多くの方法を提供してくれます。ただし、上記のように必要なときだけ組み合わせて、正しく使用しましょう。
フォールバックと古いブラウザのサポート
CSSの@supportsを使用する方法
数ヵ月ほど前に、私は自分のサイトがIE11で崩れているというツイートを受け取りました。調べてみると、とてもおかしな挙動をしていることに気がつきました。ページ上のコンテンツすべてが左上に重なっています。
IE11で崩れて表示される
上記は私のサイトで、フロントエンドデベロッパーのサイトです。なぜこうなるのか、最初は戸惑いました。しかし、思い出しました! IE11でCSS Gridがサポートされていますが、それはMicrosoftがリリースした古いバージョンのものです。解決方法は非常にシンプルで、@supportsで新しいブラウザだけCSS Gridを使用するようにします。
1 2 3 4 5 |
@supports (grid-area: auto) { body { display: grid; } } |
grid-areaを使用したのは、2017年3月から今日まで新しいCSS Gridの仕様でしかサポートされていないからです。IEは@supportsクエリをサポートしていないので、すべてのルールが無視されます。
この結果、新しいCSS Gridは、サポートするブラウザのみに使用されます。
FlexboxをCSS Gridのフォールバックとして使用する方法
Flexboxがアイテムのグリッド表示に適していないということは、フォールバックに適していないということではありません。CSS GridのフォールバックとしてFlexboxを使用することができます。
まさにそれを実現するツール「Grid to Flexbox」を作ってみました。
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 32 33 34 35 36 37 38 39 40 41 42 43 |
@mixin grid() { display: flex; flex-wrap: wrap; @supports (grid-area: auto) { display: grid; grid-gap: 16px 16px; } } @mixin gridAuto() { margin-left: -16px; > * { margin-bottom: 16px; margin-left: 16px; } @media (min-width: 320px) { > * { width: calc((99% / #{2}) - 16px); flex: 0 0 calc((99% / #{2}) - 16px); } } @media (min-width: 768px) { > * { width: calc((99% / #{3}) - 16px); flex: 0 0 calc((99% / #{3}) - 16px); } } @supports (grid-area: auto) { grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); margin-left: 0; > * { width: auto; margin-left: 0; margin-bottom: 0; } } } |
上記のフォールバックは次のように機能します。
- display: flex;およびflex-wrap: wrap;をラッパー要素に追加します。
- CSS Gridがサポートされているかを確認し、サポートされている場合はdisplay: grid;を使用します。
- セレクタ> *を使用することにより、ラッパーの直接の子要素を選択できます。選択すると、それぞれに特定の幅またはサイズを追加できます。
- もちろん、要素間にマージンが必要で、CSS Gridがサポートされている場合はgrid-gapに置換されます。
下記は、Sassのミックスインの使用例です。
1 2 3 4 |
.wrapper { @include grid(); @include gridAuto(); } |
CSS GridまたはFlexboxを不適切に使用している場合
弟のためにコードレビューをしていたところ、CSS GridとFlexboxを不適切に使用しているのがいくつかあることに気がつきました。
CSS Gridでヘッダを実装
これは、この記事を書いたきっかけの一つです。
弟がCSS Gridでヘッダを実装していることに気がつきました。
弟は「複雑で、CSS Gridは難しい、、、」と言っていました。しかし、複雑なのは不適切なテクニックを使用したからです。
弟が実装したヘッダは、下記のモックアップです。
CSS Gridで実装したヘッダ
1 2 3 4 5 6 7 8 9 |
.site-header { display: grid; grid-template-columns: 1fr 1fr 1fr 1fr 1fr 1fr; } .site-nav { display: grid; grid-template-columns: 1fr 1fr 1fr 1fr; } |
CSS Gridは2回使用されており、1回目はヘッダ全体、2回目はナビゲーションです。要素間のスペースを定義するためにgrid-columnを使用しており、他にも変なことをしていたと思うのですが、要点はつかめました!
CSS Gridでタブを実装
CSS Gridのもう一つ間違った使い方は、タブに使用することです。
CSS Gridで実装したタブ
不適切なCSSコードは次のようになります。
1 2 3 4 |
.tabs-wrapper { display: grid; grid-template-columns: 1fr 1fr 1fr; } |
このCSSを見ると、実装者はタブの数が3つだけであると想定していることが分かります。3つだけなので、レイアウトに1fr 1fr 1frを使用しているのでしょう。これは数が変更されると、簡単に崩れます。
FlexboxまたはGridの使いすぎ
古いレイアウト方法が仕事に最適かもしれないことを覚えておいてください。FlexboxやGridを使いすぎると、CSSが複雑になってしまう可能性があります。それらが煩雑であるという意味ではありませんが、この記事で説明したように、それぞれを正しく適切なコンテキストで使用する方がはるかに優れています。
例えば、ヒーローセクションがあり、そのすべてのコンテンツを水平方向の中央揃えにするとします。
すべてのコンテンツを水平方向の中央揃えに
これは、text-align: center;で実装できます。より簡単な解決策があるのに、なぜ複雑に実装するのですか?
終わりに
CSS Gridを使う場合とFlexboxを使う場合の違いについての話が多かったですね。このトピックは以前から気になっていたので、書く機会を得られてよかったです。
コメントや提案があれば、@shadeed9までお願いします。
sponsors