flexboxの残り部分を埋める書き方まとめ

8512 ワード

はじめに

とある案件でflexboxを使う際にハマってしまった、flexboxの残り幅(高さ)を埋める書き方について記載します。

やりたかったこと

スマホ用webサイトで、ヘッダー部分の高さを80px固定にし、残りの高さいっぱいにコンテンツ領域を確保する(画面スクロールしないようなイメージです)。
こんなイメージです。

HTMLのサンプルコードはこんな感じです。

<div class="parent-box">
  <div class="header">ヘッダー領域(height=80px)</div>
  <div class="content">コンテンツ領域(height=残り)</div>
</div>

ダメな書き方

css

html, body {
  height: 100%;
  margin: 0;
}

.parent-box {
  display: flex;
  flex-direction: column;
  height: 100%;
}

.header {
  height: 80px;
  background-color: #E57373;
}

.content {
  height: 100%; // ここがNG
  background-color: #90CAF9;
}

どうなったか

正しい状態 ダメな書き方の場合
OK NG

正しい状態と比べて、微妙にヘッダーの高さが足りていないように見えます。
上記の画像はiPhone SE(375 * 667)で表示した場合なのですが、ダメな書き方の場合ヘッダーの高さが71.44pxとなっていました。

何故ダメか

headerの高さ80pxとcontentの高さ100%を合計すると、parent-boxの高さを超えてしまっています。
flexboxに含まれる子要素にはデフォルトでflex-shrink: 1が設定されており、主軸方向(今回の場合は高さ方向)の幅合計が親要素を超える場合、flex-shrinkの値に応じて自動的に要素の幅が調整されます。

今回の例だと子要素は全てflex-shrink: 1なので、子要素の高さの比率で親要素の高さを按分することになります。
具体的には以下のような計算式で高さが算出されます。

# 100% = 667pxの場合
headerの高さ = 親要素の高さ * headerに指定した高さ / (parent-boxの子要素の高さの合計)
            = 100% * 80px / (80px + 100%) 
            ≒ 71.44px 

また、この書き方だとヘッダーの高さが画面の高さに依存して変動してしまうといった問題もあります。

正しい書き方その1(calcを使う)

今回のケースでは、ヘッダーの高さは固定であるため、コンテンツの高さをcalcで算出することで意図した通りになります。

css(ダメなケースからの変更点のみ抜粋)

.content {
  height: calc(100% - 80px); // ここでcalcを使う
  background-color: #90CAF9;
}

正しい書き方その2(flex-growを使う)

flexboxには余白領域を自動的に子要素に割り振るプロパティとして、flex-growがあります。
これを使うことで、コンテンツ領域の高さをflexboxの余白全てとすることができます。

css(ダメなケースからの変更点のみ抜粋)

.content {
  flex-grow: 1; // 余白に合わせて伸張する
  background-color: #90CAF9;
}

flexboxの子要素にはデフォルトでflex-grow: 0が設定されています。
コンテンツ領域のみこの値を上書きすることで、 ヘッダー領域に余白領域を割り振らず、コンテンツ領域だけを余白領域まで伸張させることができます。

どっちの書き方が良いの?

個人的にはflex-growの方が良いと思います。
calcの書き方の場合、数式中に別要素の高さを固定値で埋め込む必要があるため、修正する際に気にする部分が増えるというデメリットがありそうです。
また、flex-growを使っている方が余白領域を残さず使いたいという意図がはっきりしていて、後から読んで分かりやすいのではないかと思います。

まとめ

  • flexboxの子要素にはデフォルトで設定されているプロパティがある
    • flexboxの初期値についてはこちら
    • flexbox以外でも初期値に何が設定されているかを意識することが大切。思うように表示されない場合に初期値が原因だったりすることがある。
  • flexboxの主軸方向に幅がオーバーする場合、デフォルトの状態だとオーバーしないように子要素が自動縮小される
  • ググった結果をそのまま使わずちゃんと実験する(最重要)
    • いきなり業務コードに追加して、表示に問題なさそうに見えたのでそのまま作業を進めてしまい、後から問題が発覚。。。
    • (今回の記事作成はこのことに対する戒めが1番の目的だったりします)

あとがき

本記事を書きながら当時のことを振り返って、そもそもflexbox使う必要なかったかもしれないと思いました。
が、 flexboxに関する知識を1つ増やせたので、気にしないことにしました。