こんな使い方が!? 意外と知らないCSS Flexboxの応用

今や横並びの標準といえばFlexboxという時代ですが、そんなFlexboxでも意外と知られてないであろう使い方をご紹介します。
記述量を減らしたり、動的なサイトで重宝したり、リキッドレイアウトにも対応できちゃいます。
IEを含め主要ブラウザに対応してます。

#1. 一つが固定幅もう一つが残りの幅いっぱいの横並びボタン
<img width="804" alt="スクリーンショット 2018-05-18 3.36.04.png" src="https://qiita-image-store.s3.amazonaws.com/0/253045/ccdbbdd3-7a2c-5713-4258-ae5d230e1a21.png">
こんな感じのものを一度の横幅指定だけで作る

## html

```html
<ul class="list">
  <li class="item-short"><a href="">リスト1</a></li>
  <li><a href="">リスト2</a></li>
</ul>
```

固定幅にしたい方に固有のclassを与えてやりましょう。
##css

```css
.list {
  display: flex;
}

.list li {
  border: 1px solid #ccc;
  flex: 1 0 0%;
  box-sizing: border-box;
  text-align: center;
}

.list li a {
  display: block;
  padding: .5em;
}

.list li.item-short {
  width: 30%;

  /* flexで書き換えるとこうなる */
  flex: 0 0 30%;
　/* ただし、IEでは11でもこの指定は効かないことがあるためmax-widthとセット */
  max-width: 30%;
}

.list li:not(:last-child) {
  margin-right: 3%;
}
```

ポイントは`li`にあたっているプロパティ`flex`です。
ご存知の方は多いかと思いますがこれは`flex-grow`, `flex-shrink`, `flex-basis`のショートハンドで、今回関わってくるのは`flex-grow`と`flex-basis`です。
`flex-grow`はflexアイテムの横幅を計算してflexコンテナに対して余白がある場合その余白を埋めるかどうかの指定です。
初期値は0で整数値を指定するとその比率で余ったスペースを指定されたflexアイテムで配分するというものです。
`flex-basis`は横幅の指定です。`width`と同じです。初期値はautoです。
でも`flex: 1 0 0%;`っておかしくない？`flex: 1 0 auto;`ではダメなの？
と思った方、当然です。
これもまたIEのバグ対策です。
autoだと値が正常に計算されないのでここは数値で指定する必要があります。
ただこの数値、本当に何でも良いです(笑)
0%でも100%でも変わらないので好きな数値を指定してください。
数値が指定されていることが重要みたいです。

まとめると、flexコンテナの30%を`li.item-short`が占めて、残りの70%から`margin`を引いた分が、classの付いていない`li`の横幅になるというレイアウトです。
値の指定が一つだけで良いので計算も楽になるかと思います。

`flex`プロパティについて詳しくは[仕様書](https://developer.mozilla.org/ja/docs/Web/CSS/flex)へ

#2. 要素数が可変な横並びのボタンを均等幅に

<img width="831" alt="スクリーンショット 2018-05-18 3.10.40.png" src="https://qiita-image-store.s3.amazonaws.com/0/253045/3f04859e-811a-3fc1-15c9-ccb88514750e.png">

Flexboxを使えば一行あたりのflexアイテムの数ごとにclassを用意せずとも、flexアイテムの数に関わらず均等幅になるレイアウトが可能です。
##html
```html
<ul class="flex-list">
  <li><a href="">リスト1</a></li>
  <li><a href="">リスト2</a></li>
  <li><a href="">リスト3</a></li>
</ul>
```

はい、普通のリストです。

##CSS

```css
.flex-list {
  display: flex;
}

.flex-list li {
  flex: 1 0 0%;
  border: 1px solid #ccc;
  text-align: center;
  box-sizing: border-box;
}

.flex-list li:not(:last-child) {
  margin-right: 1%;
}

.flex-list li a {
  display: block;
  padding: .5em;
}
```

`flex`プロパティ、また出ましたね。
今回は上の応用的な考え方です。
flexアイテムの全ての`flex-grow`を1にして比率を均等にすることで`li`内にどれだけテキストが入ろうが、 また`li`がいくつになろうがそれぞれ均等幅にすることが可能です。
コードもこれだけすっきりします。

#3. さらに横並びのボタンの一部だけテキストが複数行になった場合に縦中央揃え
こんなレイアウト
<img width="803" alt="スクリーンショット 2018-05-18 5.01.48.png" src="https://qiita-image-store.s3.amazonaws.com/0/253045/43ab4c3c-6889-9a2b-2f8e-23b15a45f354.png">
特に動的なサイトの場合、`line-height`や`hegiht`を固定にできないため今まではjsのプラグインで解決している方が多かったかと思いますがFlexboxを使えばjsも要りません。
##html

```html
<ul class="flex-list">
  <li><a href="">リスト1</a></li>
  <li><a href="">リスト2<br>リスト2リスト2</a></li>
  <li><a href="">リスト3</a></li>
</ul>
```

##css

```css
.flex-list {
  display: flex;
}

.flex-list li {
  flex: 1 0 0%;
  border: 1px solid #ccc;
  text-align: center;
  box-sizing: border-box;
}

.flex-list li:not(:last-child) {
  margin-right: 1%;
}

.flex-list li a {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 100%;
  box-sizing: border-box;
  padding: .5em;
}
```

基本的に`height`の%指定はその親要素の値が未指定、もしくは%指定だと効きませんでしたが、`a`自体をflexコンテナにしてしまえば`height: 100%;`が効くようになります。
そして`align-items: center;`で縦の中央寄せを指定しています。

#まとめ
いかがでしたか？
少しでも皆さんのコーディングライフの助けになれば幸いです。
まだまだ奥が深そうなFlexbox。
もっと不思議な使い方もあるかもしれないので今後も色々試していきたいと思います。
また、既にそういったのをご存知の方がいれば是非教えてください。