レイアウト・コンポーネントの実装で役立つ、flexプロパティの実践的な使い方を徹底解説

Webページやスマホアプリのレイアウト・コンポーネントを実装する際に知っておくと便利なflexプロパティの基礎知識と実践的な使い方を紹介します。

スペースいっぱいにアイテムを伸縮させて配置したり、画像・アイコンとテキストを並べて配置したり、フォームの入力欄とボタン、複数カラムの垂直方向の揃えなど、実践的な使い方を徹底解説です。

flexプロパティの実践的な使い方を徹底解説

Digging Into the Flex Property
by Ahmad Shadeed

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

はじめに

flexプロパティがどのように機能しているのか疑問に思ったことはありませんか?
flexプロパティとは、flex-grow, flex-shrink, flex-basisのショートハンドです。最も一般的な使用例はflex: 1;で、Flexアイテムを拡張して利用可能なスペースを埋めることができます。

この記事では、ショートハンドとロングハンドのプロパティについて詳しく解説し、いつそれらをどのように使用するのかを実例とともに紹介したいと思います。

Flexboxの他のプロパティについては、下記の記事をご覧ください。

flex-growプロパティとは

flex-growは、Flexアイテムを伸長させて利用可能なスペースを埋めるための伸長係数を定義するプロパティです。flex-growの値は整数値のみを受け入れます。
参考: flex-grow(アイテムの伸長係数の比率)

注意: flex-growflex-directionプロパティに依存して幅または高さに影響を与えます。以下では特に明記しない限り、flex-directionrow(デフォルト値)に定義されていると想定してください。

flex-growを使用しない場合、Flexアイテムの幅はデフォルトで初期の幅になります。ただし、flex-grow: 1:を使用すると、使用可能なスペースはそれらの間に分散されます。

flex-growなし・ありの比較

上: flex-growなし、下: flex-growあり

ここであなたは疑問に思うかもしれません。
各Flexアイテムの幅はどのように割り当てられているのでしょうか?
良い質問です。その疑問に答えましょう。

まずは、flex-growなしの状態を見てましょう。つまり、自然なサイズです。

flex-growなし

flex-growなしの状態

Flexアイテムの幅の計算方法を理解するには、下記の計算式をご覧ください。この計算式は、Samantha Mingの記事で学びました。
参考: flex-growプロパティの算出方法(Samantha Mingの翻訳記事)

1番目の「CSS」というテキストを含むアイテムのサイズを計算してみましょう。

Flexアイテムの幅の計算方法

Flexアイテムの幅の計算方法

  • flex-grow
    アイテムの伸長係数
  • total flex-grow
    すべてのFlexアイテムのflex-grow値の合計
  • available space
    flex-grow適用前のスペース
  • Item width
    1番目のアイテムの幅

flex-grow2の値を定義した場合

上記の例では、flex-growの値はすべてのFlexアイテムで同じ値でした。今度は、1番目のアイテムをflex-grow: 2;にしてみましょう。
どのように計算されるでしょうか?
今回の例でも使用可能なスペースは、498pxで同じです。

flex-grow: 2;にした場合

flex-grow: 2;にした場合

計算式の「flex-grow」と「total flex-grow」を変更するだけです。簡単ですね。

flex-grow0の値を定義できますか?

もちろん定義できます!
flex-growプロパティは整数値を使用できるので、Flexアイテムが利用可能なスペースを取らないようにするために0を定義できます。

flex-grow: 0;にした場合

flex-grow: 0;にした場合

flex-grow: 0;は、Flexアイテムを強制的に初期の幅にしたい時に便利です。

flex-growは各Flexアイテムの幅を同じにするものではない

よくある誤解として、flex-growを使用するとアイテムの幅が同じになるというものがあります。これは正しくありません。flex-growを使用する目的は、利用可能なスペースを分散させることです。計算式で見たように、各Flexアイテムの幅は初期の幅に基づいて算出されます。

各Flexアイテムの幅を同じにしたい場合は、flex-basisを使用します。flex-basisについては、次の次のセクションで解説します。

flex-shrinkプロパティとは

flex-shrinkは、Flexアイテムを縮小させるための縮小係数を定義するプロパティです。すべてのFlexアイテムのサイズがラッパーよりも大きい場合、アイテムは縮小係数に従って収縮します。
参考: flex-shrink(アイテムの縮小係数の比率)

例を見てましょう。
2番目の中央のアイテムの幅は300pxで、flex-shrink: 1;が定義されています。これにより、すべてのFlexアイテムを収めるスペースがない場合にアイテムの幅が縮小されます。

flex-shrink: 1;にした場合

flex-shrink: 1;にした場合

以下の条件で、ブラウザはアイテムの幅を300pxに保ちます。

  • すべてのアイテムの幅の合計がラッパーの幅よりも小さい
  • ビューポートの幅がアイテムと同じかそれ以下

ビューポートのサイズを変えた場合、どのように変化するか見てましょう。

ビューポートのサイズを変えた場合

ビューポートのサイズを変えた場合

ビューポートの幅が300px未満になるまで、アイテムの幅は300pxです。

flex-basisプロパティとは

flex-basisは、Flexの係数に応じて従って使用可能なスペースを配分する前に、Flexアイテムの初期サイズを定義するプロパティです。サイズはデフォルトでは幅です(flex-direction: column;の場合は、高さ)。
参考: flex-basis(アイテムの初期サイズを定義)

flex-basisプロパティでは、widthまたはheightプロパティと同じ値を使用できます。デフォルト値はautoで、これはcontentに依存されます。content値は、Flexアイテムのコンテンツサイズに基づく自動的なサイズです。

flex-basis: 50%;にした場合

flex-basis: 50%;にした場合

上記の例では、1番目のアイテムの幅は50%です。アイテムが50%よりも大きくならないように、flex-grow0にリセットすることが重要です。

では、代わりに100%を使用するとどうなるでしょうか?
アイテムの幅は親の100%になり、他のアイテムは新しい行に折り返されます。

flex-basis: 100%;にした場合

flex-basis: 100%;にした場合

flexのショートハンドプロパティ

flex-grow, flex-shrink, flex-basisのショートハンド(省略形)です。flexのデフォルト値はautoで、flex: 0 1 auto;になります。つまり、Flexアイテムをコンテンツのサイズに応じて拡張できるということです。

ここで強調したい重要なことがあります。それは、絶対的と相対的なFlexアイテムです。いいえ、これはCSSの配置の話ではなく、Flexboxに関連するものです。

Flexアイテムの相対サイズ

Flexアイテムのサイズは、コンテンツに基づいて決められています。その結果、より多くのコンテンツを含むFlexアイテムは大きくなります。

flex: auto;にした場合

サイズは、コンテンツの量に応じて決まる

Flexアイテムの絶対サイズ

逆に、flex-basisプロパティを0に定義すると、すべてのFlexアイテムは同じサイズになります。

flex: 1;にした場合

サイズは、同じになる

flexプロパティの便利な使い方

名前からして、このプロパティは取得できる値に柔軟性があります。
いくつか例を見てましょう。

1つの単位無しの値

単位無しの値が1つしかない場合はflex-growとみなされ、ロングハンドの値は1 1 0になります。

2つの単位無しの値

値は、それぞれflex-growflex-shrinkです。flex-basisのデフォルトは0です。

1つの長さの値

長さが1つだけ定義されていた場合はflex-basisに使用されます。flex-growflex-shrinkのデフォルトは1です。

単位無し0の値

flexのショートハンドを使用して、flex-basis0にする必要がある場合です。

これはデベロッパーとブラウザの両方を混乱させるので、お勧めできません。この0がFlexの係数(growまたはshrink)のためなのか、flex-basisのためなのか、どうやって判断できますか?
紛らわしいですね。CSSの仕様を見てましょう。

2つのFlex係数が前にない単位無しの0の値は、Flex係数として解釈される必要があります。誤解や無効な宣言を回避するため、作成者はゼロの<’flex-basis’>コンポーネントを単位で指定するか、その前に2つのFlex係数を宣言する必要があります。

もしくは、代わりにpx%などの単位を追加する必要があります。

flexのショートハンドを勧める理由

grow, shrink, basisを定義する必要がある場合は、flexプロパティを使用するのがよいでしょう。

CSSの仕様によると、

制作者はflexのロングハンドのプロパティを直接使用するのはではなく、ショートハンドを使用してフレキシビリティを制御することが推奨されます。ショートハンドは一般的な用途に対応するために、指定されていないコンポーネントを正しくリセットします。

flexプロパティの使用例

ユーザーのコンポーネント

ユーザーのコンポーネント

ユーザーのコンポーネント

Flexboxのよく使用される使用例は、ユーザーのコンポーネントです。アバター画像とテキストを同じ行に配置する必要があります。

アバター(.user__avatar)にflex: 0 0 70px;を定義したことに注目してください。一部の古いブラウザではflexが設定されていないと画像が圧縮されたように見えることがあるので、これを定義することが重要です。

また、flexプロパティはwidthプロパティ(flex-direction: row;の場合)やheightプロパティ(flex-direction: column;の場合)よりも優先度が高くなります。flexプロパティの値を変更するだけでアバターのサイズを変更すると、ブラウザはwidthの値を無視します。

セクション ヘッダ

セクション ヘッダ

セクション ヘッダ

セクション ヘッダにタイトルがあり、使用可能なスペースをすべて埋める必要があります。その場合は、flex: 1;の使用が最適です。

メッセージの送信

メッセージの送信

メッセージの送信

このコンポーネントはFacebookやTwitterなどのメッセージアプリでよく見かけます。送信ボタンは固定幅で、入力欄は使用可能なスペースを埋める必要があります。

この使用例は、flex-growの便利な使用例です。flexを解説した記事の一部ではこの使用例はまったく言及されていないことがありますが、非常に便利です。

2枚のカードで最後のアイテムを揃える

2枚のカードで最後のアイテムを揃える

2枚のカードで最後のアイテムを揃える

CSS Gridが2カラムのレイアウトになっているとします。問題は、最後のアイテム(日付)が揃っていないことです。期待するのは、同じ線(レッドのライン)上に揃うことです。

Flexboxで簡単に実装できます。

flex-direction: column;を定義することで、タイトルにflex-growを使用して使用可能なスペースを埋めることができます。これにより、タイトルが短くても、最後のアイテム(日付)を揃えることができます。

もう1つ解決策があり、flex-growを使用せずに可能です。自動マージンとFlexboxのおかげです!
CSSの自動マージンについては他に便利な使い方がたくさんあります。
参考: CSSのプロパティ値「auto」を使ったテクニックのまとめ、マージンやサイズや配置やFlexboxなど

flexプロパティの使用例(複数の係数)

「複数の係数)とは、flex-growまたはflex-shrink1以外の値を使用することです。このセクションでは、その使用例を紹介します。

アクション フッタ

アクション フッタ

アクション フッタ

これもFacebookにインスパイアされたコンポーネントで、このアクション フッタには4つのアイテムがあり、右端の最後のアイテムだけ幅が狭くなっています。

伸縮アニメーション

伸縮アニメーションの仕組み

伸縮アニメーションの仕組み

面白いことに、ホバー時にFlexアイテムをアニメーションさせることができます。これは非常に簡単で、便利です。

たったこれだけでのCSSで、伸縮アニメーションが簡単に実装できます。

伸縮アニメーション

伸縮アニメーション

伸縮カード

私はCodepenのこのデモが大好きです。カードがアクティブになると、flex-grow4に変更され、カードが大きくなります。

See the Pen
🔘 Flexbox Toggles 🔘
by Shaw (@shshaw)
on CodePen.

コンテンツがラッパーよりも大きい場合

コンテンツがラッパーよりも大きい場合

コンテンツがラッパーよりも大きい場合

少し前に読者から、ある問題についてメールをいただきました。上記のように、ラッパーの中に収めたい2つの画像があります。

しかし、flex: 1;を使用しても、画像はラッパーからはみ出してしまいます。
CSSの仕様によると、

デフォルトでは、Flexアイテムは最小コンテンツサイズ(最長の単語または固定サイズの要素の長さ)未満には縮小されません。これを変更するには、min-widthまたはmin-heightプロパティを使用します。

上記の場合では画像が大きすぎるため、Flexboxはラッパーに合わせて画像を縮小しません。このビヘイビアを変更するには、min-widthを加えます。

CSSのwidthheightの最小値と最大値に関する記事で、この問題について詳しく解説してあります。
参考: Flexboxで最小幅をゼロに定義する

終わりに

以上で終了です。flexのロングハンドのプロパティの基本とその使用法について解説しました。この記事から何か新しいことを学んでいただけたら幸いです。

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

リソース

クレジット

  • Color palette from coolors.co

sponsors

top of page

©2020 coliss