【CSS】flex: 1; の闇(個人的に)

“flex”はなんとなく使えるという人も多いと思います。
かく言う私もその一人です。

しかし使えるといっても、
いつも心のどこかに何か不安な気持ちを抱えながら使っていました。

そしてそんなかすかな影に対して、
私は見て見ぬふりをしていたのかもしれません。

そう……

flex: 1;という闇に。

flex: 1; とは

まずこの場合の flex は、
display: flex;を指定した要素内にある子要素に指定するプロパティです。

flex: 1;とは、flex プロパティのショートハンド(一括指定)で、
flex:1 1 0;を省略して書いたものっぽいです。

それぞれのプロパティを細かく見てみると

flex-grow: 1;
flex-shrink: 1;
flex-basis: 0;

に分けることができます。

そしてそれぞれの役割はこちら↓

flex-grow 子要素の伸びる比率
flex-shrink 子要素の縮む比率
flex-basis 子要素のベースとなる幅の指定

……。

いや そんなことは
ちょっとググればすぐでてくるんや!

このflex: 1;結構よく見かけるけど、
いったい何のために入れているのか、いまいちしっくりこないんですよね。

ということで、
とりあえずそれぞれの役割を見ていきたいと思います。

flex-grow プロパティ

grow の意味は、伸びるみたいな意味です。グローと読みます。

単語

grow:長くなる、伸びる(英辞郎 on the WEB

成長するという意味で“グローイング”など意外とよく聞く単語なので、
なんとなくわかりそうですが、
flex-grow プロパティは少しクセがあります。

flex-grow 子要素の伸びる比率

まず、flex-grow プロパティの指定方法は、数値を入れます。

この数値というのは、ボックス内で要素が並んだ時に、
余ったスペースの比率です。この比率分子要素が伸びます。

とんでもなくわかりづらいですね。。
図にするとこんな感じです。

1つ目の要素(初期値)には何も指定せず、
2つ目の要素(grow-1)にflex-glow: 1;を指定しています。

この場合は、flex-growが指定されている要素が1つしかないので、
余ったスペースを独り占めできるという感じですね。

チェック

flex-growの初期値は、flex-grow: 0;です。
これは“伸ばさない”ということです。
なので、上図の1段目の2つ目の要素にflex-growが設定されているのですが、
余ったスペースはそのままになっています。

要素が2つにそれぞれflex-growが指定されている場合、そして同じ数値(flex-grow: 1;)が指定されている場合は、1:1 の比率で分割した分それぞれの要素を伸ばします。

同じ比率だとわかりやすいですね。
ちなみに1でも2で3でも同じ比率だったら均等に伸びるようです。

では、違う比率だとどうでしょうか。
考え方は全く同じで指定された比率分伸ばしています。

実はこの図はコンテナの幅が 400px で、子要素の幅が 100px にしており、
何も考えずに2:4だとキレイに割り切れるような気がして入れてみましたが、
ふたを開けてみたら、左が 166.672px 右が 233.328px という中途半端な値になってしまいました。。

試しにキレイに割り切れるように1:3で設定してみたのが下図です。

こちらは、左が 150px、右が250pxになりました。
grow後は、3:5という何とも見慣れない比率に。

という感じなので、余計に分かりにくく感じているのかもしれません。。
比率を変えてのflex-growの使いどころがまったく思い浮かびません。
いや、そもそも比率は合わせるのが基本的な使い方なのか……?

いつか何か画期的な活用用途があればまとめてみたいですね。

せっかく CodoPen でも作ったので載せておきます。

See the Pen flex-grow by MATSUDAI (@matsudai) on CodePen.

flex-shrink プロパティ

shrink の意味は、縮むという意味のようです。シュリンクと読みます。

単語

shrink:縮む、小さくなる(英辞郎 on the WEB

あまりなじみの無い単語ですね。
お店のとくに箱系の商品に張り付いている透明フィルムのことを“シュリンク”といったりします。
恐らく熱か何かで“縮ませて”ピタッと商品を包装するから、“シュリンク”なのでしょうか。

flex-shrink プロパティとしての機能は、改めてこちらです。

flex-shrink 子要素の縮む比率

なんとなく流れ的に、flex-grow の逆で、
はみ出た部分を比率で縮めるって感じませんか?

半分正解で、半分間違い!

でも flex-grow を理解してしまえば、
考え方自体は結構かんたんなので気負うことはないでしょう!

まず、flex-shrink プロパティの指定方法は、flex-grow と同じく数値を入れるのですが、こちらはマイナスの値は入れられません!

図にするとこんな感じです。

少しわかりにくいですが、
前提として初期値はflex-shrink: 1;です。
何も指定しなくてもボックス内に収まるのはこの指定があらかじめ入っているからなのですね。
逆に縮ませたくない場合は、flex-shirink: 0;を指定します。

それを踏まえて見てみると、なんとなくわかりそうでしょうか。
メモ書きが見づらいのでスッキリさせてみました↓

初期値は、flex-shrink: 1;と同じなので、
それぞれはみ出た分に対しての比率1:1分ずつ縮んで、結果的に同じ幅になりました。

違う比率でも考え方は同じです。
2:4だと下図のように↓

1:3だとこんな感じ↓

あんまりしっくりこない見た目ですが、
こんなもんなんでしょうと覚えておくことにします。

一応 CodePen 載せておきます。

See the Pen flex-shrink by MATSUDAI (@matsudai) on CodePen.

flex-basis プロパティ

basis の意味は、基準みたいな意味です。ベイシスと読みます。

単語

basis:土台、基準(英辞郎 on the WEB

こちらも“ベーシック”などでよく耳にするのでなじみ深いですね。

flex-basis プロパティの役割はこちら↓

flex-basis 子要素のベースとなる幅の指定

特に難しく考えずに、flex コンテナ内の子要素の幅を指定するプロパティです。
width プロパティがある場合、flex-basis プロパティが auto でない限り、flex-basis プロパティが優先されます。

width とは違うの?

flex コンテナ(display: flex;が指定されたボックス)内であれば、width も flex-basis も変わらないのではないのかなぁと思いました。

仮に、
flex コンテナ内の子要素に width プロパティだけ指定して、flex プロパティは何もしないとしたら、flex プロパティは初期値と同じ挙動をします。(たぶん。)

width: 200px;
/* flex-grow: 0; ← 初期値 */
/* flex-shrink: 1; ← 初期値 */
/* flex-basis: auto; ← 初期値 */

つまり、flex コンテナが 100px だとしたら、縮むということ!
これは flex-basis を設定しても同じってことじゃない?

/* flex-grow: 0; ← 初期値 */
/* flex-shrink: 1; ← 初期値 */
flex-basis: 200px;

じゃあ、flex プロパティの影響を受けないようにしたら?

width: 200px;
flex-grow: 0; /* 伸びない */
flex-shrink: 0; /* 縮まない */
flex-basis: none; /* 指定しない */

当然、flex コンテナが 100px だとしたら、縮まないではみ出ます!

でもそれってやっぱり、flex-basis に設定するのと同じでは?

flex-grow: 0; /* 伸びない */
flex-shrink: 0; /* 縮まない */
flex-basis: 200px;

……。

混乱しましたが、width で幅を指定しようが、flex-basis で幅を指定しようが、なんだか結果は変わらないようなので、おとなしく flex-basis を使おうと思います。

ちょっと、待ったあああ

今は横並びの話をしていますが、実は縦で並ぶとき、flex-basis は縦幅に変化します。
話がどんどんそれてしまうのでここでは割愛しますが、

flex-directin プロパティというものが関わってくるのですねぇ。そして align-items プロパティというものも出張ってきます。この話はまた今度まとめてみます。

何が言いたいのかというと、
flex-basis = width ではないということだけは、しっかり頭に入れておかなければいけませんね。

恐らく、レスポンシブ対応させるときに主に活躍するような気がします。

flex-basis: 0; とはどういう状態?

さて、闇に近づいてきました……。
flex-basis: 0;というのは、まぁ幅が 0 です笑
要素内に何かあれば、可能な範囲で最小になるようです。

例えば文字が入っていれば改行可能な位置まで潰されます。
これは word-break プロパティや、overflow-wrap プロパティに影響を受けるみたいです。

一方、flex-basis: auto;は、要素内のサイズに合わせて幅が決まります。
ただし、width が同時に設定されていると、width が優先されます。
そして、flex-basis: 0;だと当然 flex-basis が優先されます。

See the Pen flex-basis by MATSUDAI (@matsudai) on CodePen.

改めて flex: 1; とは

flex: 1;とは、flex プロパティのショートハンド(一括指定)で、
flex:1 1 0;を省略したものです。

とりあえず比率1で、伸び縮みする!
flex-basis: 0;で幅が 0 だけど、flex-grow: 1;によりスペース分伸びるので問題無し!
そして意外と重要なのが、width (height)が指定されていてもbasis: 0;でリセットしてくれる!

といったところでしょうか。

さて、ここからが本題です。

なぜ、flex: 1; は、
flex: 1 1 0;なのか……。

それは、flex プロパティのショートハンドは「値の数」と「単位の有無」によって、その数値に影響されるプロパティが変わってしまうという仕様が、影響しているのかもしれません。

値の数 単位 プロパティ
1 あり flex-basis
なし flex-grow
2 あり flex-grow / flex-basis
なし flex-glow / flex-shrink
3 あり flex-grow / flex-shrink / flex-basis
なし flex-grow / flex-shrink / flex-basis
※flex-basisが 0 や autoなどの場合

なるほど、値が1つで単位が無いから、
flex: 1;は、flex-grow プロパティの値が1になって、その他の数値が初期値になるのですね!

……。

……。

flex-basis の初期値って、
auto じゃなかったけ?

私のような素人がネットで軽く調べただけじゃ、この闇の答えにはたどり着けませんでした。。
そしてそんな答えがすぐに見つからないような“スタイル”が、当たり前のように使われている。
それこそが、この flex: 1; の闇。

私はそう思います。

……。

ちなみに、CSS のプロパティには、
「初期値」ともう一つ「デフォルト値」なるものが存在するということらしい、

初期値(Initial Value)

CSS プロパティの値が何も指定されていない場合に適応される値です。
今回の件だと例えば、flex コンテナ内の子要素に何も設定していないのに勝手に縮むのはflex-shrink: 1; という初期値が影響しているというわけですね。

デフォルト値(Default Value)

CSS プロパティに対して何らかの値が指定されていて、その値が明示的に設定されていない場合に適応される値です。

ひょっとして、
flex: 1;の場合、初期値ではなく、デフォルト値になり、なんやかんやでflex-basis: 0;と同じになるという仕様なのではないかと思いました……。

いや、バグやろ!

デベロッパーツールを見ると間違いなくflex: 1 1 0;を示しているので、間違った情報ではない……。

みんな、なんだかんだ便利だからそのまま使ってる説を私は推したい。

また、
flex プロパティには、flex: 1;と使い分けて、便利に使えるショートハンドがあります。

flex: initial;

flex: 0 1 auto; と同じ効果のショートハンドです。
値の initisal の意味の通り、これこそが初期値ですね。

flex: auto;

flex: 1 1 auto; と同じ効果のショートハンドです。
width を設定してある場合、flex: 1;が幅をリセットするのに対して、こちらはそのまま width の幅に依存するという使い分けができますね。
flex: 1;こそ、flex-basisの初期値 auto なので、こちらになりそうなのに、、なんか納得いかないです。

flex: none;

flex: 0 0 auto; と同じ効果のショートハンドのようです。
私は考えるのをやめた。

まとめ

そういうものとして、覚える。

今回いろいろ調べながら、flex: 1;についてまとめてみましたが、なぜflex-basis: 0;になるのか明確な答えにたどり着けることはできませんでした。いつかひょんなことから答えにたどり着けることを願って今はただ、flex: 1;という闇を甘んじて受け入れようと思います。

トップへ戻る