flexプロパティの実践的な使い方を徹底解説
Post on:2020年8月27日
Webページやスマホアプリのレイアウト・コンポーネントを実装する際に知っておくと便利なflexプロパティの基礎知識と実践的な使い方を紹介します。
スペースいっぱいにアイテムを伸縮させて配置したり、画像・アイコンとテキストを並べて配置したり、フォームの入力欄とボタン、複数カラムの垂直方向の揃えなど、実践的な使い方を徹底解説です。
Digging Into the Flex Property
by Ahmad Shadeed
下記は各ポイントを意訳したものです。
※当ブログでの翻訳記事は、元サイト様にライセンスを得て翻訳しています。
- はじめに
- flex-growプロパティとは
- flex-shrinkプロパティとは
- flex-basisプロパティとは
- flexのショートハンドプロパティ
- flexプロパティの便利な使い方
- flexのショートハンドを勧める理由
- flexプロパティの使用例
- flexプロパティの使用例(複数の係数)
- 終わりに
はじめに
flexプロパティがどのように機能しているのか疑問に思ったことはありませんか?
flexプロパティとは、flex-grow, flex-shrink, flex-basisのショートハンドです。最も一般的な使用例はflex: 1;で、Flexアイテムを拡張して利用可能なスペースを埋めることができます。
この記事では、ショートハンドとロングハンドのプロパティについて詳しく解説し、いつそれらをどのように使用するのかを実例とともに紹介したいと思います。
Flexboxの他のプロパティについては、下記の記事をご覧ください。
flex-growプロパティとは
flex-growは、Flexアイテムを伸長させて利用可能なスペースを埋めるための伸長係数を定義するプロパティです。flex-growの値は整数値のみを受け入れます。
参考: flex-grow(アイテムの伸長係数の比率)
1 2 3 4 5 |
<div class="wrapper"> <div class="item item-1"></div> <div class="item item-2"></div> <div class="item item-3"></div> </div> |
1 2 3 4 5 6 7 8 |
.wrapper { display: flex; flex-wrap: wrap; } .item { flex-grow: 1; } |
注意: flex-growはflex-directionプロパティに依存して幅または高さに影響を与えます。以下では特に明記しない限り、flex-directionがrow(デフォルト値)に定義されていると想定してください。
flex-growを使用しない場合、Flexアイテムの幅はデフォルトで初期の幅になります。ただし、flex-grow: 1:を使用すると、使用可能なスペースはそれらの間に分散されます。
上: flex-growなし、下: flex-growあり
ここであなたは疑問に思うかもしれません。
各Flexアイテムの幅はどのように割り当てられているのでしょうか?
良い質問です。その疑問に答えましょう。
まずは、flex-growなしの状態を見てましょう。つまり、自然なサイズです。
flex-growなしの状態
Flexアイテムの幅の計算方法を理解するには、下記の計算式をご覧ください。この計算式は、Samantha Mingの記事で学びました。
参考: flex-growプロパティの算出方法(Samantha Mingの翻訳記事)
1番目の「CSS」というテキストを含むアイテムのサイズを計算してみましょう。
Flexアイテムの幅の計算方法
1 |
Item width = ( (flex-grow / total flex-grow) * available space) + initial item width |
-
- flex-grow
- アイテムの伸長係数
-
- total flex-grow
- すべてのFlexアイテムのflex-grow値の合計
-
- available space
- flex-grow適用前のスペース
-
- Item width
- 1番目のアイテムの幅
1 |
Item width = ( (1 / 3) * 498) + 77 = 241 |
flex-growに2の値を定義した場合
上記の例では、flex-growの値はすべてのFlexアイテムで同じ値でした。今度は、1番目のアイテムをflex-grow: 2;にしてみましょう。
どのように計算されるでしょうか?
今回の例でも使用可能なスペースは、498pxで同じです。
flex-grow: 2;にした場合
計算式の「flex-grow」と「total flex-grow」を変更するだけです。簡単ですね。
flex-growに0の値を定義できますか?
もちろん定義できます!
flex-growプロパティは整数値を使用できるので、Flexアイテムが利用可能なスペースを取らないようにするために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;にした場合
1 2 3 4 |
.item-2 { width: 300px; 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アイテムのコンテンツサイズに基づく自動的なサイズです。
1 2 3 4 5 |
.item-1 { flex-grow: 0; flex-shrink: 0; flex-basis: 50%; } |
flex-basis: 50%;にした場合
上記の例では、1番目のアイテムの幅は50%です。アイテムが50%よりも大きくならないように、flex-growを0にリセットすることが重要です。
では、代わりに100%を使用するとどうなるでしょうか?
アイテムの幅は親の100%になり、他のアイテムは新しい行に折り返されます。
1 2 3 4 5 |
.item-1 { flex-grow: 0; flex-shrink: 0; flex-basis: 100%; } |
flex-basis: 100%;にした場合
flexのショートハンドプロパティ
flex-grow, flex-shrink, flex-basisのショートハンド(省略形)です。flexのデフォルト値はautoで、flex: 0 1 auto;になります。つまり、Flexアイテムをコンテンツのサイズに応じて拡張できるということです。
ここで強調したい重要なことがあります。それは、絶対的と相対的なFlexアイテムです。いいえ、これはCSSの配置の話ではなく、Flexboxに関連するものです。
Flexアイテムの相対サイズ
1 2 3 4 |
.item { /* デフォルト値、flex:1 1 1 auto;と同じ */ flex: auto; } |
Flexアイテムのサイズは、コンテンツに基づいて決められています。その結果、より多くのコンテンツを含むFlexアイテムは大きくなります。
サイズは、コンテンツの量に応じて決まる
Flexアイテムの絶対サイズ
逆に、flex-basisプロパティを0に定義すると、すべてのFlexアイテムは同じサイズになります。
1 2 3 4 |
.item { /* flex: 1 1 0%;と同じ */ flex: 1; } |
サイズは、同じになる
flexプロパティの便利な使い方
名前からして、このプロパティは取得できる値に柔軟性があります。
いくつか例を見てましょう。
1つの単位無しの値
1 2 3 |
.item { flex: 1; } |
単位無しの値が1つしかない場合はflex-growとみなされ、ロングハンドの値は1 1 0になります。
2つの単位無しの値
1 2 3 |
.item { flex: 1 1; } |
値は、それぞれflex-growとflex-shrinkです。flex-basisのデフォルトは0です。
1つの長さの値
長さが1つだけ定義されていた場合はflex-basisに使用されます。flex-growとflex-shrinkのデフォルトは1です。
1 2 3 4 |
.item { flex: 100px; /* flex: 1 1 100px;と同じ */ } |
単位無し0の値
flexのショートハンドを使用して、flex-basisを0にする必要がある場合です。
1 2 3 |
.item { flex: 0; } |
これはデベロッパーとブラウザの両方を混乱させるので、お勧めできません。この0がFlexの係数(growまたはshrink)のためなのか、flex-basisのためなのか、どうやって判断できますか?
紛らわしいですね。CSSの仕様を見てましょう。
2つのFlex係数が前にない単位無しの0の値は、Flex係数として解釈される必要があります。誤解や無効な宣言を回避するため、作成者はゼロの<’flex-basis’>コンポーネントを単位で指定するか、その前に2つのFlex係数を宣言する必要があります。
もしくは、代わりにpxや%などの単位を追加する必要があります。
1 2 3 4 |
.item { flex: 0%; /* flex: 1 1 0%;と同じ */ } |
flexのショートハンドを勧める理由
grow, shrink, basisを定義する必要がある場合は、flexプロパティを使用するのがよいでしょう。
CSSの仕様によると、
制作者はflexのロングハンドのプロパティを直接使用するのはではなく、ショートハンドを使用してフレキシビリティを制御することが推奨されます。ショートハンドは一般的な用途に対応するために、指定されていないコンポーネントを正しくリセットします。
flexプロパティの使用例
ユーザーのコンポーネント
ユーザーのコンポーネント
Flexboxのよく使用される使用例は、ユーザーのコンポーネントです。アバター画像とテキストを同じ行に配置する必要があります。
1 2 3 4 5 6 7 |
<div class="user"> <img class="user__avatar" src="shadeed.jpg" alt="" /> <div> <h3>Ahmad Shadeed</h3> <p>Author of Debugging CSS</p> </div> </div> |
1 2 3 4 5 6 7 8 9 10 11 |
.user { display: flex; flex-wrap: wrap; align-items: center; } .user__avatar { flex: 0 0 70px; width: 70px; height: 70px; } |
アバター(.user__avatar)にflex: 0 0 70px;を定義したことに注目してください。一部の古いブラウザではflexが設定されていないと画像が圧縮されたように見えることがあるので、これを定義することが重要です。
また、flexプロパティはwidthプロパティ(flex-direction: row;の場合)やheightプロパティ(flex-direction: column;の場合)よりも優先度が高くなります。flexプロパティの値を変更するだけでアバターのサイズを変更すると、ブラウザはwidthの値を無視します。
1 2 3 4 5 6 |
.user__avatar { /* 幅は100pxです、70pxにはなりません */ flex: 0 0 100px; width: 70px; height: 70px; } |
セクション ヘッダ
セクション ヘッダ
セクション ヘッダにタイトルがあり、使用可能なスペースをすべて埋める必要があります。その場合は、flex: 1;の使用が最適です。
1 2 3 4 5 6 7 8 |
.page-header { display: flex; flex-wrap: wrap; } .page-header__title { flex: 1; } |
メッセージの送信
メッセージの送信
このコンポーネントはFacebookやTwitterなどのメッセージアプリでよく見かけます。送信ボタンは固定幅で、入力欄は使用可能なスペースを埋める必要があります。
1 2 3 4 5 6 7 8 9 |
form { display: flex; flex-wrap: wrap; } input { flex: 1; /* 他のスタイルを記述 */ } |
この使用例は、flex-growの便利な使用例です。flexを解説した記事の一部ではこの使用例はまったく言及されていないことがありますが、非常に便利です。
2枚のカードで最後のアイテムを揃える
2枚のカードで最後のアイテムを揃える
CSS Gridが2カラムのレイアウトになっているとします。問題は、最後のアイテム(日付)が揃っていないことです。期待するのは、同じ線(レッドのライン)上に揃うことです。
Flexboxで簡単に実装できます。
1 2 3 4 5 |
<div class="card"> <img src="thumb.jpg" alt=""> <h3 class="card__title">Title short</h3> <time class="card__date"></time> </div> |
flex-direction: column;を定義することで、タイトルにflex-growを使用して使用可能なスペースを埋めることができます。これにより、タイトルが短くても、最後のアイテム(日付)を揃えることができます。
1 2 3 4 5 6 7 8 9 |
.card { display: flex; flex-direction: column; } /* 解決策1 */ .card__title { flex-grow: 1; } |
もう1つ解決策があり、flex-growを使用せずに可能です。自動マージンとFlexboxのおかげです!
CSSの自動マージンについては他に便利な使い方がたくさんあります。
参考: CSSのプロパティ値「auto」を使ったテクニックのまとめ、マージンやサイズや配置やFlexboxなど
1 2 3 4 |
/* 解決策2 */ .card__date { margin-top: auto; } |
flexプロパティの使用例(複数の係数)
「複数の係数)とは、flex-growまたはflex-shrinkで1以外の値を使用することです。このセクションでは、その使用例を紹介します。
アクション フッタ
アクション フッタ
これもFacebookにインスパイアされたコンポーネントで、このアクション フッタには4つのアイテムがあり、右端の最後のアイテムだけ幅が狭くなっています。
1 2 3 4 5 6 7 8 9 10 11 12 |
.actions { display: flex; flex-wrap: wrap; } .actions__item { flex: 2; } .actions__item.user { flex: 1; } |
伸縮アニメーション
伸縮アニメーションの仕組み
面白いことに、ホバー時にFlexアイテムをアニメーションさせることができます。これは非常に簡単で、便利です。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
.palette { display: flex; flex-wrap: wrap; } .palette__item { flex: 1; transition: flex 0.3s ease-out; } .palette__item:hover { flex: 4; } |
たったこれだけでのCSSで、伸縮アニメーションが簡単に実装できます。
伸縮アニメーション
伸縮カード
私はCodepenのこのデモが大好きです。カードがアクティブになると、flex-growが4に変更され、カードが大きくなります。
See the Pen
🔘 Flexbox Toggles 🔘 by Shaw (@shshaw)
on CodePen.
コンテンツがラッパーよりも大きい場合
コンテンツがラッパーよりも大きい場合
少し前に読者から、ある問題についてメールをいただきました。上記のように、ラッパーの中に収めたい2つの画像があります。
1 2 3 4 5 6 7 |
.wrapper { display: flex; } .wrapper img { flex: 1; } |
しかし、flex: 1;を使用しても、画像はラッパーからはみ出してしまいます。
CSSの仕様によると、
デフォルトでは、Flexアイテムは最小コンテンツサイズ(最長の単語または固定サイズの要素の長さ)未満には縮小されません。これを変更するには、min-widthまたはmin-heightプロパティを使用します。
上記の場合では画像が大きすぎるため、Flexboxはラッパーに合わせて画像を縮小しません。このビヘイビアを変更するには、min-widthを加えます。
1 2 3 4 |
.wrapper img { flex: 1; min-width: 0; } |
CSSのwidthとheightの最小値と最大値に関する記事で、この問題について詳しく解説してあります。
参考: Flexboxで最小幅をゼロに定義する
終わりに
以上で終了です。flexのロングハンドのプロパティの基本とその使用法について解説しました。この記事から何か新しいことを学んでいただけたら幸いです。
コメントや提案があれば、@shadeed9までお願いします。
リソース
- Grid for layout, Flexbox for components
- Learn Box Alignment
- A closer look at Absolute and Relative flex-items.
- flex-grow is weird. Or is it?
- CSS Flexbox: 5 Real World Use Cases
- Solved by Flexbox
クレジット
- Color palette from coolors.co
sponsors