複数行に対応したテキストの縦方向の中央寄せ決定版（？）

#はじめに

高さがあらかじめ決まっている要素内で文字列を縦方向に中央寄せしたい時様々な方法がありますが、個人的にあまりしっくりくるものがありませんでした。
それぞれの方法から、メリットデメリットを見てみます。

ちなみに、以下のようなHTMLとCSSを共通で使用するとします。

```html:HTML
<div class="parentElement">
  <div class="childElement">アライさん、またやってしまったねぇ</div>
</div>
<div class="parentElement">
  <div class="childElement">ふわああぁ！いらっしゃぁい！よぉこそぉ↑ジャパリカフェへ～！どうぞどうぞ！ゆっぐりしてってぇ！いやま゛っ↓てたよぉ！やっとお客さんが来てくれたゆぉ！嬉しいなあ！ねえなんにぃのんむぅ 色々あるよぉ、これね、紅茶って言うんだってぇハ↓カセに教えてもらったンの！</div>
</div>
```

```css:CSS
.parentElement {
  overflow: hidden;
  width: 640px;
  height: 100px;
  margin: 20px;
  border: 2px #999 solid;
  background-color: #f7f7f7;
}

.childElement {
  padding: 0 15px;
  color: #000;
  font-size: 14px;
  background-color: #d1d1d1;
  box-sizing: border-box;
}
```
こんな感じの表示になります。

![sample01.png](https://qiita-image-store.s3.amazonaws.com/0/169473/54ea9080-a9c8-dfca-3fd0-0dadd1d57812.png)

わかりやすいように背景色をつけています。

#様々な方法を見てみる

それぞれの方法でどのように表示されるのか見てみましょう。

##`line-height` で何とかする

`line-height` を使って親要素と同じ値にすれば何とかなるんじゃない？

```css:CSS
.childElement {
  line-height: 100px;
}
```

![sample02.png](https://qiita-image-store.s3.amazonaws.com/0/169473/1af3907a-2a84-cf42-f4fd-b9306e0d3758.png)

ありゃ、複数行にわたる長いテキストは1行分しか表示されない……

###特徴

- 子要素の高さは親要素いっぱいに広がる（`line-height` が親要素の高さ以上の指定だった場合）

####メリット

- 簡単に書ける
- ほとんどのブラウザで対応できる

####デメリット

- 複数行に対応できない
- テキストのベースラインの関係上、少し下にずれているように見えてしまう
- 親要素の高さを変更する場合に同時に変更しなければならない

##`display: table-cell;` を利用する

`display: table-cell;` を使えば楽なのでは？

```css:CSS
.parentElement {
  display: table;
}

.childElement {
  display: table-cell;
  vertical-align: middle;
}
```

![sample03.png](https://qiita-image-store.s3.amazonaws.com/0/169473/462d071f-aaab-4b76-335d-c7088ced9b87.png)

いい感じですね

###特徴

- 子要素の高さは親要素いっぱいに広がる

####メリット

- 複数行に対応できる
- テキストのベースラインが考慮された中央寄せができる

####デメリット

- テーブルのセル扱いになるので様々な制約が出てしまう
- `display: table-cell;` にした場合、`position: relative;` が無効になる

##`position` と `transform` の組み合わせ

`position` と `transform` を組み合わせることによって中央に寄せてみようという、最近の流行り（？）の方法。

```css:CSS
.parentElement {
  position: relative;
  z-index: 0;
}

.childElement {
  position: absolute;
  top: 50%;
  z-index: 0;
  width: 100%;
  transform: translate(0, -50%);
}
```

![sample04.png](https://qiita-image-store.s3.amazonaws.com/0/169473/5f7133e9-8da2-b2cd-70e6-a158ba983036.png)

いろんな要素に応用できます。

###特徴

- ブラウザやディスプレイ（スマホやRetinaなどの高解像度ディスプレイ）によっては小数点単位で中央に寄る
- 子要素の高さは内包しているコンテンツに依存する

####メリット

- 複数行に対応できる
- テーブルのセルにあったような制約がない

####デメリット

- ちょっと複雑
- 場合によっては若干ぶれているように見える可能性がある

##`display: flex;` を使う

個人的にはこれが最適解な気がします。

```css:CSS
.parentElement {
  display: flex;
  align-items: center;
}

.childElement {
  flex: 1;
}
```

![sample05.png](https://qiita-image-store.s3.amazonaws.com/0/169473/7a593e72-b5b7-3fea-af3e-ece81fe4b5a8.png)

わー簡単にできました。

###特徴

- 子要素の高さは内包しているコンテンツに依存する

####メリット

- 簡単に書ける
- 複数行に対応できる
- テーブルのセルにあったような制約がない

####デメリット

- ブラウザによっては対応していない

#「あれ？ flex便利だけど対応してないブラウザあるじゃん！」

いやいやいや、待ってください、確かに `display: flex;` はCSS3から追加された新しいスタイルですが、まずは [Can I use...](http://caniuse.com/) を見ましょう。

[Can I use... - Flexible Box Layout Module](http://caniuse.com/#feat=flexbox)

Internet Explorer に関しては 10 から部分的に対応していることがわかります。この程度の記述であればIE特有のバグも発生しません（多分）。
~~ぶっちゃけ、IE10以下に関してはもう対応するだけ馬鹿らしいので意地でも使い続ける人の事は考慮しなくていいと思う。~~

また、Androidに関しても 4.4 から完全対応しているので、スマホ向けに関しては現状ではほとんど気にする必要はありません。

#おわりに

このエントリーでは文字列を縦方向に中央寄せする方法として書きましたが、普通にブロック要素の縦方向の中央寄せとしても `display: flex;` は有用だと思います。
Flexible Box は今までのめんどくさいCSSテクニックから解放される救世主と言っても過言ではないと思うので、積極的に使っていきたい。