【中央揃え編】CSS限界オタクと学ぶレイアウトCSSサンプル集

こんにちは。フロントエンド開発で一番好きなのはCSS、Mhousetreeです。
普段は[CSSアニメーションで遊んだり](https://mhousetree.github.io/stylesheet-overdose/)しています。
（頑張って作ったのでよかったら見てね！！！！！）

何かと使う中央揃え。なんとなく覚えているものを順番に試して中央に来たらOK！と思っていませんか？
現在ではかなりいろんな種類の方法があり、それぞれ異なる特徴を持っています。

この記事ではCSSでよく使う（気がする）レイアウトパターンの中で、センタリングに関するものをまとめました！

## まえがき

この記事では各実例を独自の指標で評価して示しています。
長い記事になる予定なので、部分的に読まれる場合の参考になさってください。

実用性：記述量や例外（中身の文章が長い・改行がある要素など）への対応力など。
よく見る度：コーディングしていて出てくる頻度(n=1)。
お前しか勝たん度：独自性が強い・他の方法では代替しづらいものを高く評価。

サンプルは基本的にSCSSで書いています。

また、実例として示されたCSSのうち、`sample`クラスセレクタおよびその下の階層で指定している
内容が重要で、直接要素セレクタで指定しているものに関しては例を見やすくするためだけの、
本質（レイアウト）とは関係のないものです。ご留意ください。

## 中央揃えについて
本編に入る前に、中央揃えとは何かをはっきりさせておきましょう。

中央揃えとは、**親要素に対して子要素が上下・左右の中央に来ること**を指します。
全ての中央揃えには必ず親要素と子要素(HTML要素ではないテキストノードも含む)が存在します。
自然言語的に表現すると、○○の中央に××を置く、と言った場合の、○○が親要素で××が子要素です。

今回提示するサンプルでは、親要素の背景色が緑、子要素の背景色が半透明の黄色になっています。

## インライン要素の左右中央揃え
ほぼ一択だと思います。センタリングしたい要素の親要素に `text-align: center` を指定します。

実用性：★★★★★
よく見る度：★★★★★
お前しか勝たん度：★★★★★
<p class="codepen" data-height="300" data-default-tab="css,result" data-slug-hash="OJZdVMp" data-editable="true" data-user="mhousetree" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/mhousetree/pen/OJZdVMp">
  Untitled</a> by mhousetree (<a href="https://codepen.io/mhousetree">@mhousetree</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

子要素は上の例の場合素のテキストですが、インライン要素であれば `span` 等でももちろんOKです。

## インライン要素の上下中央揃え
大きく分けて3パターンあります。
上下中央揃えは改行が発生したときの挙動にそれぞれ特徴があるので、
各パターンにつき改行なしのサンプル（上）と改行ありのサンプル（下）を用意しました。

1つ目と2つ目は見た目は同じですが、センタリングしたい子要素にプロパティを指定するか、
親要素に指定するかという違いがあります。

### Flexを使う
実用性：★★★★★
よく見る度：★★★
お前しか勝たん度：★★★★
<p class="codepen" data-height="300" data-default-tab="css,result" data-slug-hash="jOxdPKv" data-editable="true" data-user="mhousetree" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/mhousetree/pen/jOxdPKv">
  Untitled</a> by mhousetree (<a href="https://codepen.io/mhousetree">@mhousetree</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>

Flex、要素を1列に並べるときに使うものだと思っていませんか？
要素をセンタリングしたい時にもFlexは便利です。

先ほど登場した左右中央揃えの場合も、この例の`align-items` の代わりに 
`justify-content: space-between` で一応中央に揃いますが、
改行する場合はうまくいかないのでまあ普通に `text-align: center`した方がいいと思います。

### line-heightを親要素の高さと同じにする
実用性：★★★
よく見る度：★★★
お前しか勝たん度：★★
<p class="codepen" data-height="300" data-default-tab="css,result" data-slug-hash="ZEowGqN" data-editable="true" data-user="mhousetree" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/mhousetree/pen/ZEowGqN">
  Untitled</a> by mhousetree (<a href="https://codepen.io/mhousetree">@mhousetree</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>

複数行になった時の見た目は最悪ですが、間違いなく1行の時はこれでもいいと思います。

### 複数のインライン要素を中央に揃える

3つ目のパターンは2つ以上の異なる高さを持つインライン要素の場合に使える手段で、こちらは
センタリングしたい子要素に指定する形になります。

実用性：★★★★
よく見る度：★★★
お前しか勝たん度：★★★★★
<p class="codepen" data-height="300" data-default-tab="css,result" data-slug-hash="ZEowGyV" data-editable="true" data-user="mhousetree" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/mhousetree/pen/ZEowGyV">
  Untitled</a> by mhousetree (<a href="https://codepen.io/mhousetree">@mhousetree</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>

実用例としては、和欧混植を`span`使って実現したときにベースラインガタガタなんだが！？という時などに使えます。
これも複数行になった時も割と想像通りのレイアウトになる感じがします。適材適所ですね。

## インライン要素の上下左右中央揃え
インライン要素の上下左右中央揃えは、上記の上下・左右の中央揃えを組み合わせる形で実装するのがいいと思います。
また、ボタンや、ボタンっぽい見た目のリンクなんかだと下手に中央揃えにしようとするより、
ブロックレベル要素にしてしまって、上下・左右それぞれに均一な `padding`を設定した方が意味的に良い場合もあります。
ぱっと見同じように見える、ボタンっぽいリンクをいくつか例示しますので解読してみてください。

<p class="codepen" data-height="300" data-default-tab="css,result" data-slug-hash="VwxgjQQ" data-editable="true" data-user="mhousetree" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/mhousetree/pen/VwxgjQQ">
  Untitled</a> by mhousetree (<a href="https://codepen.io/mhousetree">@mhousetree</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>

ボタンっぽいリンクの場合だと、クリックできる範囲の関係でブロックレベル要素にしてしまった方が明らかに良いですね。


## ブロックレベル要素の左右中央揃え

ぶっちゃけインラインよりよく使うと思います。そして複雑です。

### `margin: 0 auto;`

実用性：★★★★★
よく見る度：★★★★★
お前しか勝たん度：★★★

<p class="codepen" data-height="300" data-default-tab="css,result" data-slug-hash="yLjZJYd" data-editable="true" data-user="mhousetree" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/mhousetree/pen/yLjZJYd">
  Untitled</a> by mhousetree (<a href="https://codepen.io/mhousetree">@mhousetree</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>

CSSを書いたことがある人なら必ず1度は目にした事があるであろう呪文。
仕組みとしては子要素の左右のマージンを自動で設定することで、なんか左右の余白が同じ広さになるように
（＝センタリングされるように）レイアウトされる、というもの。
この理屈初めに知った時はこう実装した人がすげえと思いました。

`padding` と `margin` の違いも怪しいセンタリング初心者が調べてもすぐ出てくるのに、
マージンの値はスペース区切りで2個与えるとそれぞれ上下の値・左右の値として扱われる、とかいう
初心者からしたら知らんがな！みたいな仕組みを使っている。
そう、`0` の部分は0じゃなくてもよくて上下に空けたい余白の分にすればいいんだということです。

でも1行で書けるのでめっちゃ便利だと思います。センタリングしたい子要素に指定する形なので、個人的には `body` とか `main` とか、1個だけセンタリングしたい場合によく使います。
親要素の中にある複数の子要素をまとめてセンタリングしたい場合とかは次に紹介する方法の方がおすすめです。

### Flexを使う
方法としてはインライン要素の時に紹介したものと大体一緒です。
Flexでセンタリングして、さらに中身のテキストをセンタリングするために `text-align: center` も
指定するパターンなどは頻出かなと思います（映画のスタッフロールみたいになります）。

#### 要素1個の場合

実用性：★★★★
よく見る度：★★★★
お前しか勝たん度：★★★

<p class="codepen" data-height="300" data-default-tab="css,result" data-slug-hash="abGXmvE" data-editable="true" data-user="mhousetree" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/mhousetree/pen/abGXmvE">
  Untitled</a> by mhousetree (<a href="https://codepen.io/mhousetree">@mhousetree</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>

並べたい要素が1個の場合の中央揃えには `justify-content: center` を使うことになります。
`flex-direction` が初期値の `row` になっているため、並べる方向と平行な方向に対しての位置を設定する
`justify-content` で中央揃えをします。

#### 要素複数の場合

実用性：★★★★★
よく見る度：★★★★★
お前しか勝たん度：★★★

<p class="codepen" data-height="300" data-default-tab="css,result" data-slug-hash="poVGEyN" data-editable="true" data-user="mhousetree" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/mhousetree/pen/poVGEyN">
  Untitled</a> by mhousetree (<a href="https://codepen.io/mhousetree">@mhousetree</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>

縦に並べた要素を全て左右中央でセンタリングしたい場合、先述した `margin: 0 auto`でもいいのですが、
共通した親要素の下にある場合はこちらの方法を使うのもいいと思います。
要素を縦に並べるため `flex-direction` を `column` にして、並べる方向と垂直な方向に対しての位置を設定する
`align-items` で中央揃えをします。

4つ目の子要素内のテキスト「サンプルプル」は、`p` タグの `text-align` が初期値の `center` のままなので、
左寄せになっています。
これも中央揃えにしたい場合は、
```css
p {
  text-align: center;
}
```
を指定すると達成できます（先述した映画のスタッフロールになります）。

## ブロックレベル要素の上下中央揃え
### Flexを使う

実用性：★★★★
よく見る度：★★
お前しか勝たん度：★★★★★

<p class="codepen" data-height="300" data-default-tab="css,result" data-slug-hash="poVGEVw" data-editable="true" data-user="mhousetree" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/mhousetree/pen/poVGEVw">
  Untitled</a> by mhousetree (<a href="https://codepen.io/mhousetree">@mhousetree</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>

インラインで説明したものと同じです。

## ブロックレベル要素の上下左右中央揃え

おしゃれなウェブサイトを作ろうとすると結構出番があって、そして、かなり多様です。
上下左右中央揃えを活用しまくっている実例としては [私のポートフォリオ](https://mhousetree.github.io/) があります。よかったらみてください（宣伝）。

### Flexを使う
実用性：★★★★
よく見る度：★★★★★
お前しか勝たん度：★★★

<p class="codepen" data-height="300" data-default-tab="css,result" data-slug-hash="XWqOjoB" data-editable="true" data-user="mhousetree" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/mhousetree/pen/XWqOjoB">
  Untitled</a> by mhousetree (<a href="https://codepen.io/mhousetree">@mhousetree</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>

Flexを使った左右の中央揃えと上下の中央揃えを合わせたパターンです。
親要素に3行書くだけで中央揃えできて普通に便利です。
ただ、後述するGridを使った方法の方が1行少ないので今はそっちで良いかなという感じがしてきています。

### Gridを使う
実用性：★★★★★
よく見る度：★★★★★
お前しか勝たん度：★★★★★

<p class="codepen" data-height="300" data-default-tab="css,result" data-slug-hash="RwyvowW" data-editable="true" data-user="mhousetree" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/mhousetree/pen/RwyvowW">
  Untitled</a> by mhousetree (<a href="https://codepen.io/mhousetree">@mhousetree</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>

最近出てきた(体感)すげーやつ。親要素に2行書くだけでセンタリングできて最高です。
`place-items` プロパティは `align-items` と `justify-items` を一括で指定できるプロパティだそうです。

### `position: absolute`

実用性：★★★★★
よく見る度：★★★★
お前しか勝たん度：★★★★★

<p class="codepen" data-height="300" data-default-tab="css,result" data-slug-hash="GRdzNJq" data-editable="true" data-user="mhousetree" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/mhousetree/pen/GRdzNJq">
  Untitled</a> by mhousetree (<a href="https://codepen.io/mhousetree">@mhousetree</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>

忘れてはいけない、これはこれで便利なやつです。
行数は多いし複雑なんですがこいつじゃないとダメな場面も多いので実用性高めに評価しています。

特徴としては

- 兄弟の子要素に影響されないところ
- （中央揃えを紹介する記事で特徴としてこれ出すの微妙ですが）中央以外の任意の割合の配置に対応できるところ

があります。

この記事で紹介した中では一番記述量が多いので簡単に解説すると、
- 親要素の `position: relative;` で子要素の絶対配置の始点を親要素のサイズに設定
- 子要素の `position: absolute;` で絶対配置
- `top: 50%; left: 50%;` で、親要素の中心点（高さ・幅が50%の点）を子要素の始点に
  ただし、子要素の左上の点がこの位置に来るので子要素自身はこの時点では右下にずれている
- `translate: -50% -50%;` で、子要素の高さ・幅の半分だけ左上にずらす

という仕組みで中央揃えを実現しています。
つまり中央以外の配置にしたい場合は `top`, `left` の値を任意の値にすると実現できます。
（相対配置と絶対配置についてこの記事で語るには少々長くなりすぎるので、ぜひ調べてみてください！）

まとめて解説した方がわかりやすいと思ったので上下左右中央揃えの項目で紹介しましたが、上下のみ・左右のみでも
この方法は便利です（というか、この方法の方が良い場合があるという感じ）。


## 背景画像をセンタリングしたい場合

実用性：★★★★★
よく見る度：★★
お前しか勝たん度：★★★★★

<p class="codepen" data-height="300" data-default-tab="css,result" data-slug-hash="poVGNPZ" data-editable="true" data-user="mhousetree" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/mhousetree/pen/poVGNPZ">
  Untitled</a> by mhousetree (<a href="https://codepen.io/mhousetree">@mhousetree</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>

`img` タグで挿入される通常の画像はここまでに説明した方法でセンタリングする事ができますが、
背景画像の場合はこのようになります。


## あとがき
いかがでしたでしょうか。CSS早口オタクに皆さん慄かれたことでしょう。

今回紹介した以外にも左右中央揃えを Grid でやるとか、いろんな方法があるとは思いますが
なるべく実用的というか、中央揃えをしたいと思った時にほんとうに使うものを掲載しました。

使い分けはなかなか難しいというか、ものによってはその人の価値観によるところもあると思います。
もし「これは特にこういう時に使うといい」とか、「これはこういう理由で表示が早い」みたいな情報をご存知でしたら
ぜひコメントで教えていただけるととても勉強になるので嬉しいです。

本当はセンタリング以外も書こうと思ってたんですがセンタリングだけでも相当な長さになってしまったので、
（モチベがあれば）レイアウトサンプル集シリーズにしようと思っています。

それでは良きCSSライフを！