flexbox justify-content align-items を理解して、レスポンシブなナビゲーションメニューを作る。

この記事の技術的な目的は<font color="red">**要素を横並び、高さを揃えてテキストを上下左右中央寄せにする**</font>です。

前半は理論的な事をグダグダ述べていますので興味のない方は「最後に」まで飛んで下さい！

## 本題

flexboxと言えばfloatと同様、横並びによく使うcssですね。floatの場合、clearを後続の要素に足さなくてはならないので、flexboxの方が人気が高いcssだと思います。

私もflexboxをよく使うのですが、そもそもflexboxって何者何だろうと思い調べたところいろいろ気付く事があったのでここを使って情報共有したいと思います。

## そもそもflexboxとは？

[引用元](https://developer.mozilla.org/ja/docs/Web/CSS/CSS_Flexible_Box_Layout/Basic_Concepts_of_Flexbox)

>通常フレックスボックスと呼ばれている Flexible Box Module は一次元のレイアウトモデルとして、またインターフェイス中のアイテム間でスペースの分配をする機能と強力な位置合わせをする機能を提供するものとして設計されました。

とあります。ポイントを抽出し、要約します。

・正式名称は「Flexible Box Module」
　→フレキシブル、つまり融通の利くということ。全然どうでもいい個人的な考え方だがflex自体が横並びな訳ではなくて、あくまでも融通が利くので縦並びの要素が横並びにも出来るのかなって思う。

・一次元レイアウトモデルである。
　→つまり縦なら縦、横なら横にしかレイアウト出来ない。

・スペースの分配をする機能と強力な位置合わせをする機能を提供する
　→横並べに加え、要素の中央寄せとかもセットで出来ますよーってこと。これから解説するjustify-content、align-itemsに繋がるところ。

## flexboxの考え方
上記で出た「一次元レイアウトモデル」ですが、「ある一定の方向」でしか配置できませんよって事でした。
でこの「ある一定の方向」というのが、かなり重要で、ブロックが積み重なる「主軸」と、これと交差する「交差軸」の２つの軸が存在します。

でここで難しいのが、あくまで「ブロックが積み重なる」方向なので、縦にブロックが積み重なっていれば縦が主軸になるし、横にブロックが積み重なっていれば横が主軸になります。文章だけだと分かりずらいので以下に図を用意しました。

![flexbox交差軸.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/420031/04b2ef07-97f0-a0d7-a163-dede63ca6609.jpeg)

![flexbox主軸.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/420031/d790fe3a-7d5b-9914-5d83-0bab4b198cca.jpeg)

基本的には横を使うことが殆どなので、横のパターンを中心に覚えておきましょう。
で、ここまでのことを考えるとflexboxつまりdisplay:flex;を使って横並びにすることは、<font color="red">**主軸を切り替えてる**</font>と考えると面白いですね！

## 主軸、交差軸の調整方法
ここからが本題。
なんとなく2つの軸が存在することを知れたと思いますが、実際にコードを書いて行きたいと思います。
では以下のようなナビゲーションバーを作ったと仮定しましょう。

```html:html
<nav>
  <ul>
    <li><a href="#">menu1</a></li>
    <li><a href="#">menu2</a></li>
    <li><a href="#">menu3</a></li>
    <li><a href="#">menu4</a></li>
    <li><a href="#">menu5</a></li>
  </ul>
</nav>
```

```css:css
/* reset */
*{
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}
/* main contents */
nav ul{
  display: flex;
  list-style: none;
}
nav ul li{
  width: 100%;
}
nav a{
  display: block;
  height: 100%;
  padding: 10px 5px;
  background-color: #d2691e;
  color: #ffffff; 
  text-align: center;
  border-width: 10px;
  border-color: #ff964b #b44b00 #783200 #ffc8a0;
  border-style: solid;
  text-decoration: none;
}
```

画面は以下のようになります。

![スクリーンショット 2020-11-18 23.32.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/420031/e25e7bc7-5471-a0fd-0923-3c988e01a35c.png)

ちょっとレトロなボタン風にしてしまいましたがｗまぁよくある横並びのメニューです。

では各メニューの文字数が変わってしまったらどうでしょうか？コードを変更してみましょう。

```html:html
<nav>
  <ul>
    <li><a href="#">menu1</a></li>
    <li><a href="#">menu2</a></li>
    <li><a href="#">menu3. case by long text.</a></li>
    <li><a href="#">menu4</a></li>
    <li><a href="#">menu5</a></li>
  </ul>
</nav>
```

画面は以下のようになります。

![スクリーンショット 2020-11-18 23.42.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/420031/3962635d-6eb8-8673-f45a-36cb9c7c7f19.png)

画面をみてもらうとわかるのですが、navのaに当てたheight:100%;のおかげで各メニューの高さは揃っています。（確認したい場合はnav aのheight:100%;を外して確認してみてください）ですが中のテキストはどうでしょうか？長いテキストは真ん中に来ていますが、他のテキストは上寄せになっています。

**主軸と交差軸という言葉を使って言い換えてみましょう。**

navのulにdisplay:flex;を当てているので<font color="red">**主軸は横**</font>となります。これは簡単ですね。そして交差軸はこの場合<font color="red">**テキストの配置**</font>となります。現状テキストは上寄せになるので、<font color="red">**これを交差軸方向の中央寄せにすればいい**</font>ことになります。

ちょっと文章だけだと分かりづらいので画面に図を加えました。

![主軸交差軸_図_1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/420031/aacd4555-feb9-6770-3a1a-3146782ef9fa.jpeg)

なんとなく軸の区分けと、やりたいことが明確になったかと思います。
ではこの主軸と交差軸を変化させるためのcssを当てていきましょう。

## justify-content, align-items
display:flex;とセットで使うことが多いCSSを２つご紹介します。
それぞれ、軸、使用用途、プロパティ、値を図にしています。
※値に関しては代表的な物のみ紹介します。

| 軸 | 使用用途の例 | プロパティ | 値 |
|:----------:|:------------:|:------------:|:------------:|
| 主軸 | メニューを中央に配置 | justify-content | center |
| ↑ | メニューを等間隔に配置(両端揃え) | ↑ | space-between |
| ↑ | メニューを等間隔に配置(真中揃え) | ↑ | space-around |
| 交差軸 | テキストを縦方向に中央寄せ | align-items | center |

代表的な物を紹介しましたが、今回はとりあえずalign-items:center;を使えば良さそうです。
ただどこにcssを書けば良いでしょうか？

目的をもう一度整理しましょう。今回は<font color="red">**aタグ内のテキストを縦方向（交差軸方向）に中央寄せ**</font>にしたいですよね？

ならば簡単です。今回でいうnavのaの中にCSSを書けばいいですね。ですが実はこれだけでは思い通りには動きません。justify-content,align-itemsはdisplay:flex;とセットで使うことで効力を発揮するのでdisplay:flex;も一緒に追加します。

ここで勘のいい方なんかは思うかも知れません。「横並びにする必要もないのでdisplay:flex;を使うべきではない」と。でも物は使いよう、発想の転換ですし、実際にこのような実装をしているのを見たことがあるので、そこまで気にすることはないと自分は思います。

少し話がそれましたが、実際にコードを書いていきます。

```css:css(追加分のみ記載)
nav a{
  display: flex;
  align-items: center;
}
```

画面を確認します。

![スクリーンショット 2020-11-19 1.04.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/420031/f01446a2-61e6-ab84-77f7-c0f7c99350a7.png)

見てみると、確かに縦方向（交差軸方向）に中央寄せになりましたが、横方向(主軸方向)が左寄せになってしまいました。これはdisplay:flex;を使ったことが原因で、これを使うと子要素が１つの要素のような認識をされてしまうからです。text-align:center;はテキストに対して有効なので要素そのものには効きません。

ではどうすれば良いでしょう？
やりたいことをまとめます。流れ的になんとなくわかると思いますが、今度は<font color="red">**aタグ内のテキストを横方向（主軸方向）に中央寄せ**</font>ですね。

ここで使うのがjustify-content:center;です。aタグにコードを追加しましょう。

```css:css(追加分のみ記載)
nav a{
  justify-content: center;
}
```

画面を確認します。

![スクリーンショット 2020-11-19 2.07.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/420031/5de3f122-c359-2ad5-ad1d-abeccf12297c.png)

どうでしょうか？これで目的の縦横中央寄せのナビゲーションバーの完成です。お疲れ様でした！

## 最後に
最後に完成系のコードを載せておきます。説明していない部分としては、もとから当ててあったdisplay: block;を消してあります。理由はdisplay:flex;を後から当てたので、displayプロパティの重複で不要になったからです。

```css:css(完成形)
/* reset */
*{
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}
/* main contents */
nav ul{
  display: flex;
  list-style: none;
}
nav ul li{
  width: 100%;
}
nav a{
  text-decoration: none;
  background-color: #d2691e;
  color: #ffffff; 
  text-align: center;
  padding: 10px 5px;
  /* 不要になったので削除↓ */
  /* display: block; */
  /* メニューの高さを揃える */
  height: 100%;
  /* 各メニューのborderデザイン */
  border-width: 10px;
  border-color: #ff964b #b44b00 #783200 #ffc8a0;
  border-style: solid;
  /* テキストを上下左右中央に配置する */
  display: flex;
  align-items: center;
  justify-content: center;
}
```

以上です。最後までご静聴ありがとうございました。