主軸方向のフレックスアイテムの比率の制御
このガイドでは、主軸に沿ってアイテムの寸法と自由度を制御することができる 3 つのプロパティ、 flex-grow
, flex-shrink
, flex-basis
を見ていきます。これらのプロパティがどのようにフレックスアイテムを伸縮させるかについて完全に理解することが、 CSS フレックスボックスをマスターするための鍵です。
最初に見てみる
3 つのプロパティは、フレックスアイテムの自由度を以下の観点から制御します。
flex-grow
: このアイテムが得る正の余白はどれくらいか。flex-shrink
: このアイテムから縮小できる負の余白はどれくらいか。flex-basis
: 伸長や縮小が発生する前のアイテムの寸法はいくつか。
プロパティは通常、一括指定の flex
プロパティを使用して表します。以下のコードは flex-grow
プロパティを 2
に、 flex-shrink
を 1
に、 flex-basis
を auto
に設定します。
.item {
flex: 2 1 auto;
}
主軸に合わせて動作する重要概念
flex
プロパティを理解するためには、伸縮が起こる前のフレックスアイテムの自然なサイズを知ることが役立ちます。さらに、主軸に沿ったすべてのフレックスアイテムの自然なサイズを組み合わせたものと主軸自体のサイズとの差である自由空間の概念を理解することも重要です。
フレックスアイテムの寸法の変更
フレックスアイテムをレイアウトするために利用できる空間を決定するために、ブラウザーはアイテムがどれくらいの大きさから始まるのかを知る必要があります。絶対的な長さの単位で適用される幅や高さを持たないアイテムは、どのようにして計算されるのでしょうか。
CSS では、 min-content
と max-content
キーワードを <length>
単位の代わりに使用することができます。一般的に、 min-content
は要素が最も長い単語を収めることができる最小のサイズであり、 max-content
は要素が折り返されることなくすべてのコンテンツを収めるために必要なサイズです。
下記の例は、異なる文字列を持つ 2 つの段落要素を格納しています。最初の段落の幅は min-content
です。テキストが利用利用可能なソフトラップの機会をすべて使用して、はみ出すことなく可能な限り小さくなっていることに注目してください。これがその文字列の min-content
サイズです。基本的に、文字列の中で最も長い単語がサイズを決定しています。
2 つ目の段落は、 max-content
の値を持ち、その逆を行います。ソフトラップの機会を取ることなく、コンテンツに合わせて必要なだけ大きくなります。コンテナー内で狭すぎるとはみ出します。
<p class="min-content">
I am sized with min-content and so I will take all of the soft-wrapping
opportunities.
</p>
<p class="max-content">
I am sized with max-content and so I will take none of the soft-wrapping
opportunities.
</p>
.min-content {
width: min-content;
border: 2px dotted rgb(96 139 168);
}
.max-content {
width: max-content;
border: 2px dotted rgb(96 139 168);
}
この動作と、min-content
および max-content
がどのような効果を持つかについては、後述の flex-grow
と flex-shrink
の説明で覚えておいてください。
正と負の余白
正と負の余白の概念も理解する必要があります。フレックスコンテナーに正の余白がある場合、コンテナーの中にはフレックスアイテムを表示するのに要求される以上の空間があります。例えば、横幅 500px
のコンテナーで、 flex-direction
を row
に設定し、横幅 100px
のフレックスアイテムを 3 つ格納した場合、 200px
の正の余白があります。コンテナー内を埋め尽くしたい場合は、この正の余白をアイテムの間に分配することができます。
フレックスコンテナーに負の余白があるというのは、フレックスコンテナー内で利用できる空間よりも、フレックスアイテムの自然なサイズの合計値の方が大きい場合です。上記の 500px
幅のコンテナー内で、 3 つのフレックスアイテムの幅が 100px
ではなく 200px
の場合、それらの自然な幅の合計は 600px
となり、 100px
の負の余白が生じます。この空間をアイテムから除去してコンテナー内に収まるようにしないと、アイテムがはみ出してしまいます。
フレックス一括指定のプロパティの成分を知るためには、この正の余白の分配と負の余白の除去を理解する必要があります。
以下の例では、flex-direction
を row
(行) に設定されているので、アイテムの寸法は幅に基づいて決定されます。すべてのアイテムの幅の合計とコンテナーの幅を比較して、正と負の余白を計算します。それぞれの例を flex-direction: column
で試すこともできます。主軸が列になり、アイテムの高さと、アイテムが入っているコンテナーの高さを比較して、正と負の余白を計算する必要が出てきます。
flex-basis
プロパティ
flex-basis
プロパティは、正または負の余白を分配する前のフレックスアイテムの初期サイズを指定します。このプロパティの初期値は auto
です。このプロパティは、 width
および height
プロパティと同じ値を受け入れ、 content
キーワードも受け入れます。
flex-basis
が auto
に設定されている場合、アイテムの初期サイズは、主要サイズが設定されていれば、その <length-percentage>
サイズになります。例えば、あるアイテムに width: 200px
が設定されている場合、 200px
がそのアイテムの flex-basis
になります。パーセント値は、フレックスコンテナーの内部の主要サイズに対する相対値です。 width: 50%
が設定されている場合、このアイテムの flex-basis
はコンテナーのコンテンツボックスの幅の半分になります。そのようなサイズが設定されていない場合、つまりアイテムが自動サイズである場合、 auto
はそのコンテンツのサイズに解決され(上記の min-
および max-content
のサイズの説明を参照)、 flex-basis
はアイテムの max-content
という意味になります。
この例では、 flex-grow
と flex-shrink
の両方を 0
に設定した、柔軟性のないフレックスアイテムが 3 つ含まれています。 最初のアイテムの幅は 150px
で、 flex-basis
は 150px
に設定されていますが、他の 2 つのアイテムは幅が設定されていないため、コンテンツの幅または max-content
に応じてサイズが設定されます。
<div class="box">
<div>One</div>
<div>Two</div>
<div>Three</div>
</div>
.box > * {
border: 2px solid rgb(96 139 168);
border-radius: 5px;
background-color: rgb(96 139 168 / 0.2);
flex: 0 0 auto;
}
.box {
width: 500px;
border: 2px dotted rgb(96 139 168);
display: flex;
}
.box :first-child {
width: 150px;
}
auto
キーワードとそれ以外の有効な width
値に加えて、content
キーワードを flex-basis
として使用することができます。この場合、flex-basis
は、アイテムに width
が設定されていてもコンテンツの寸法に基づきます。これは、設定されている幅を除去し、flex-basis
として auto
を使用するのと同じ効果を生み出します。 max-content
を設定するのと似ていますが、 content
の値を設定すると、交差軸上の寸法に基づいて aspect-ratio
を計算することができます。
余白の分配の際にフレックスアイテムのサイズを完全に無視したい場合は、 flex-basis
を 0
に設定し、 flex-grow
に 0
以外の値を設定します。この値を実際に見ていく前に、 flex-grow
を学びましょう。
flex-grow
プロパティ
flex-grow
プロパティは、フレックス伸長係数を指定します。これは、正の余白が分配されたときに、フレックスアイテムがフレックスコンテナー内の他のフレックスアイテムに対してどれだけ伸長するかを決定します。
すべてのアイテムの flex-grow
係数が同じであれば、正の余白はすべてのアイテムに均等に分配されます。この場合、一般的には flex-grow: 1
を設定しますが、任意の値、例えば 88
、100
、1.2
などが設定できます。コンテナー内ですべてのフレックスアイテムに同じ係数が設定され、正の余白がある場合、その余白は均等に分配されます。
flex-grow
と flex-basis
の組み合わせ
flex-grow
と flex-basis
がどのように相互作用するかという点については混乱しやすいものです。コンテンツの長さが異なる 3 つのフレックスアイテムに、次のような flex
ルールを適用した場合を考えてみましょう。
.class {
flex: 1 1 auto;
}
この場合、 flex-basis
の値は auto
で、アイテムには幅が設定されていないので、寸法は自動調整されます。つまり、使用される flex-basis
は各アイテムの max-content
の寸法です。アイテムを配置した後、フレックスコンテナー内には正の余白があります。下記画像では斜線を引いた領域で示されています。斜線を引いた領域は正の余白で、 flex-grow
係数に基づいて 3 つのアイテムに分配されます。
コンテンツの寸法に等しい flex-basis
を使用しています。すなわち、利用できる空間全体(フレックスコンテナーの幅)から引き算で分配可能な余白が求められ、残りの余白は 3 つのアイテム間で均等に分配されます。最も大きなアイテムは、もともとより大きなサイズから始まり、他と同じ空間が分配されるので、最も大きなままになります。
元の要素の大きさが異なっていても、3 つのアイテムを同じ大きさにしたいのであれば、 flex-basis
成分を 0
にしてください。
.class {
flex: 1 1 0;
}
ここでは、空間分配の計算のために、各アイテムの寸法を 0
に設定しています。これによって、すべての空間が分配に利用できるようになります。すべてのアイテムが同じ flex-grow
係数をを持っていますので、それぞれ等しい大きさの空間を取得します。この結果、 3 つの同じ幅のフレックスアイテムができます。
このライブサンプルで、 flex-grow
係数を 1 から 0 に変更して、動作の違いを確認してみてください。
<div class="box">
<div>One</div>
<div>Two</div>
<div>Three にはもっとコンテンツがあります</div>
</div>
.box > * {
border: 2px solid rgb(96 139 168);
border-radius: 5px;
background-color: rgb(96 139 168 / 0.2);
flex: 1 1 0;
}
.box {
width: 400px;
border: 2px dotted rgb(96 139 168);
display: flex;
}
アイテムに個別の flex-grow 係数を与える
flex-grow
と flex-basis
を一緒に使用すると、異なる flex-grow
係数を設定することで、個々のアイテムの大きさを制御することができます。すべての空間を分配できるように flex-basis
を 0
にしておくと、それぞれのアイテムに異なる flex-grow
係数を割り当てることで、異なる大きさのフレックスアイテムを作成することができます。
下記の例では、最初の2つのアイテムには flex-grow
の係数として 1
を使用し、3つ目には倍の 2
を使用しています。 flex-basis: 0
をすべてのアイテムに設定すると、利用できる空間は次のように配分されます。
- すべての兄弟フレックスアイテムの
flex-grow
係数値が一斉に追加されます(この場合合計は 4 です)。 - フレックスコンテナー内で正の自由空間をこの合計値で割ります。
- 自由空間は個々の値に応じて分配されます。この場合、最初のアイテムは 1 部、 2 つ目は 1 部、 3 つ目は 2 部を取得します。ということは、 3 つ目のアイテムは最初と 2 つ目のアイテムの 2 倍の大きさということになります。
<div class="box">
<div class="one">One</div>
<div class="two">Two</div>
<div class="three">Three</div>
</div>
.box > * {
border: 2px solid rgb(96 139 168);
border-radius: 5px;
background-color: rgb(96 139 168 / 0.2);
flex: 1 1 0;
}
.box {
border: 2px dotted rgb(96 139 168);
display: flex;
}
.one {
flex: 1 1 0;
}
.two {
flex: 1 1 0;
}
.three {
flex: 2 1 0;
}
ここでは、どんな正の値も使用できることを覚えておいてください。重要なのはアイテム間の比率です。大きな数字や小数を使用することができますが、それはあなた次第です。これを検証するために、この例の flex-grow
の値を .25
、.25
、.50
に変えてみてください。同じ結果になるはずです。
flex-shrink
プロパティ
flex-shrink
プロパティでは、フレックス縮小係数を指定します。これは、負の余白が分配されたときに、フレックスコンテナー内の他のフレックスアイテムに対して、フレックスアイテムがどれだけ縮小するかを決定します。
このプロパティは、フレックスアイテムの flex-basis
の結合値が大きすぎてフレックスコンテナー内で収まらず、あふれてしまう場合に対処します。アイテムの flex-shrink
が正の値である限り、アイテムはコンテナー内であふれないように縮小されます。
flex-grow
は伸長可能なアイテムに利用できる空間を追加するために使用しますが、 flex-shrink
は、アイテムがあふれず、コンテナー内で確実に収まるように空間を縮小するために使用します。
次の例では、 3 つの 200px
幅のフレックスアイテムが 500px
幅のコンテナー内にあります。 flex-shrink
を 0
に設定すると、アイテムは縮小されず、コンテナー内からあふれてしまいます。
<div class="box">
<div>One</div>
<div>Two</div>
<div>Three にはもっとコンテンツがあります</div>
</div>
.box > * {
border: 2px solid rgb(96 139 168);
border-radius: 5px;
background-color: rgb(96 139 168 / 0.2);
flex: 0 0 auto;
width: 200px;
}
.box {
width: 500px;
border: 2px dotted rgb(96 139 168);
display: flex;
}
flex-shrink
値を 1
に変更すると、各アイテムは同じ量だけ縮小され、すべてのアイテムがコンテナー内で収まります。それぞれのアイテムから負の余白が比例して除去され、それぞれのフレックスアイテムは最初の幅よりも小さくなります。
flex-shrink
と flex-basis
の組み合わせ
一見、 flex-shrink
は flex-grow
と同じように、要素を伸長させるのではなく、縮小させる方法で動作するように見えるかもしれません。しかし、注意すべき重要な違いがいくつかあります。
フレックスベースサイズの概念は、フレックスアイテム間で負の余白をどのように配分するかに影響します。負の余白を分配するときは、フレックス縮小係数にフレックスベースサイズを掛けます。これにより、アイテムがどれだけ縮むことができるかに比例して、負の余白が分配されます。例えば、大きなアイテムが顕著に縮小する前に、小さなアイテムがゼロに縮小することはありません。
小さなアイテムは min-content
の寸法未満に縮小されることはありません。これは、使用できるソフトラップの機会をすべて使用した場合の要素の最小寸法です。
以下の例では、 min-content
が下限になり、 flex-basis
が内容物の大きさに解決されていることがわかります。フレックスコンテナーの幅を 700px などに変更してからフレックスアイテムの幅を小さくすると、最初の 2 つのアイテムは折り返されますが、 min-content
の寸法より小さくなることはありません。ボックスが小さくなると、3 つ目のアイテムが縮小します。
<div class="box">
<div>Item One</div>
<div>Item Two</div>
<div>Item Three はもっとコンテンツがあるため、もっと大きくなります</div>
</div>
.box > * {
border: 2px solid rgb(96 139 168);
border-radius: 5px;
background-color: rgb(96 139 168 / 0.2);
flex: 1 1 auto;
}
.box {
border: 2px dotted rgb(96 139 168);
width: 500px;
display: flex;
}
実際には、この縮小動作は妥当な結果をもたらします。コンテンツが完全に消えてしまったり、コンテンツの最小サイズより小さくなってしまったりするのを防ぎます。上記のルールは、コンテナーに合わせて縮小する必要があるコンテンツには理にかなっています。
アイテムに別の flex-shrink
要素を与える
flex-grow
と同様に、それぞれのフレックスアイテムに異なる flex-shrink
係数を与えることができます。これにより、たとえば、あるアイテムを兄弟アイテムよりも急速に縮小させたり、まったく縮小させないようにしたい場合に、既定の動作を変更することができます。
この例では、最初のアイテムの flex-shrink
係数は 1
、 2 つ目のアイテムは 0
(まったく縮小しない)、 3 つ目のアイテムは 4
で、合計の縮小係数は 5
です。したがって、 3 つ目のアイテムは最初のアイテムの約 4 倍の速さで縮小しますが、どちらも min-content
幅以下に縮小することはありません。 flex-grow
と同様に、ここでも小数や大きな数値を使用することができます。
<div class="box">
<div class="one">One</div>
<div class="two">Two</div>
<div class="three">Three</div>
</div>
.box > * {
border: 2px solid rgb(96 139 168);
border-radius: 5px;
background-color: rgb(96 139 168 / 0.2);
width: 200px;
}
.box {
display: flex;
width: 500px;
border: 2px dotted rgb(96 139 168);
}
.one {
flex: 1 1 auto;
}
.two {
flex: 1 0 auto;
}
.three {
flex: 2 4 auto;
}
フレックスアイテムの寸法の設定をマスターする
フレックスアイテムのサイズ調整がどのように動作するのかを理解するには、このガイドで説明した下記の要素を考慮する必要があります。
何がアイテムの基本的な寸法を決定するか
flex-basis
がauto
に設定されていて、アイテムに幅が設定されている場合は、その幅に応じた寸法になります。flex-basis
がauto
に設定されていて、アイテムの幅が設定されていない場合は、コンテンツのサイズに基づいた寸法になります。flex-basis
が長さまたはパーセント値の単位で、0 ではない場合は、これがアイテムの寸法になります(min-content
が下限になります)。flex-basis
が0
に設定されている場合は、アイテムの寸法は空間共有の計算には考慮されません。
利用できる余白があるか
アイテムが伸長するのは、正の余白がある場合のみであり、負の余白がないとアイテムは縮小しません。
- すべてのアイテムの幅(列の場合は高さ)を合計したとき、その合計がコンテナーの幅(または高さ)の合計よりも小さい場合は、正の余白があり、
flex-grow
の出番となります。 - すべてのアイテムの幅(列の場合は高さ)を合計した場合、その合計がコンテナーの幅(または高さ)の合計よりも大きい場合は、負の余白があり、
flex-shrink
が効いてきます。
余白を分配する別の方法
アイテムに余白を追加したくない場合は、「フレックスコンテナー内のアイテムの配置」で説明している配置プロパティを使って、アイテム間やアイテム周辺の余白を管理できることを思い出してください。 justify-content
プロパティを使用すると、アイテム間やアイテム周辺の余白の分配が可能になります。また、フレックスアイテムに auto のマージンを使用すると、スペースを吸収してアイテム間に隙間を作ることができます。
これらのフレックスプロパティがすべて利用できるため、最初のうちは少し試行錯誤が必要かもしれませんが、ほとんどのレイアウト課題が可能であることがわかります。