📘

【CSS】Flexboxの中でボタンが大きくなる理由

2022/12/13に公開


display:flexが指定された要素の中に、ボタンを入れると縦方向に大きくなってしまいます。
解決策は、align-selfcenterflex-endなどを指定することです。

CSSはググれば簡単に解決方法が見つかることもあり、今までまともに勉強をしてこなかったので、ここで改めて何故そうなるのか?を調べてみます。

Flexboxとは

アイテムのグループを 1 つの次元でレイアウトするために設計されたレイアウトのための機構です。レイアウトのための機構としてもう一つ代表的なものにGridがありますが、こちらは 2 つの次元でレイアウトすることに適しています。

flex

ある要素のdisplay属性の値にflexを指定するとFlexboxでのレイアウトができるようになり(Flex Containerと呼ばれる)、子要素が全て Flex Item になります。
また、冒頭でも述べましたがFlexboxは 1次元 でのレイアウトを行うための機構です。display:flexを指定した最初の状態では、横軸が主軸に指定されるため内側の要素は横一列に並ぶことになります。この主軸はflex-directionを使うことによって縦か横かを指定できます。

<div class="container">
  <h1> Hello FlexBox</h1>
  <h4> subtitle</h4>
  <input placeholder="inputfield"></input>
  <button>Button</button>
</div>
.container {
  display: flex;
  justify-content: space-between;
  border: solid black;
}


Flexboxについては内容が盛り沢山で時間がいくらあっても足りないので、タイトルにある通りボタンが大きくなる理由を調べます。
もっと詳しく知りたい場合は、collisさんの翻訳記事、もしくはMDNがおすすめです。
https://coliss.com/articles/build-websites/operation/css/css3-flexbox-properties-by-scotch.html
https://developer.mozilla.org/ja/docs/Learn/CSS/CSS_layout/Flexbox

flex-item

Flexboxの子要素は全てFlex Itemになります。ということは、ボタンもFlex Itemになっているはずです。それでは、Flex Itemとは何なのでしょうか?
Flex Itemは次のようなプロパティを持ちます。

プロパティ 説明 初期値
align-self グリッドやフレックスのアイテムの align-items の値を上書する auto
flex-basis フレックスアイテムの初期の大きさ auto
flex-grow フレックスアイテムが大きくなる係数 0
flex-shrink フレックスアイテムが小さくなる係数 1
order フレックスアイテムを並べる順番 0
flex-basisflex-growも少し難しいのですが、align-selfに注目します。align-itemsの値を上書きするとありますが、align-itemsとは何でしょうか?

align-items

グリッドレイアウトやフレックスボックスでのアイテムの位置を制御するためのプロパティ。
フレックスボックスでは、交差軸方向のアイテムの配置を制御します。交差軸とはFlexboxの説明で述べた主軸と垂直に交差する軸のことです。初期状態では主軸が横方向なので交差軸は縦方向です。
https://developer.mozilla.org/ja/docs/Web/CSS/align-items
aligin-itemsの初期値はnormalです。

align-items:normal

normalの効果はレイアウトモード(FlexboxやGridのこと)に依存します。
フレックスボックスではstrechとして動作するため、フレックスアイテムも全てstrechとなります。
↑これがボタンが大きくなる理由の答えですね。
strechの説明には、幅や高さの制約の大きさが拡張されますとあるので、ボタンが可能な限り大きくなってしまったようです。

よって、ボタンなどの伸ばしたくない要素にalign-self:flex-endなどと指定すると縦に伸びなくなり、全ての要素に適用したい場合はalign-itemscenterなどを指定すると全てが中心に揃います。

button {
  align-self: flex-end;
}

.container {
  display: flex;
  justify-content: space-between;
  align-items: center;
  border: solid black;
}

感想

解決策を見つけるだけなら一瞬で終わりますが、何故を追求すると無限に時間が溶けて行きそうです。調べている中でも分からないこと(フレックスコンテナーのベースライン、マージンボックスのcross-size)や面白そうな機能(displayの2値構文)などがありCSS沼は底なしです。

本記事を書くきっかけとなった、個人的なアドベントカレンダーも読んでいただけると嬉しいです。(ジャンルはごった煮です。)
https://k41531.github.io/2022-AdventCalendar/

Discussion