【CSS】もう二度と「なんで中央寄せされてないの？！」なんて言わない

## はじめに

これは「Happiness Chain Advent Calendar 2023」の3日目の記事です。

https://adventar.org/calendars/9414/

今まで何度となく同じミスを繰り返し、そのたびにググってきたので、いい加減に自分でまとめたいと思います。

:::note warn
この記事では `flexbox` や縦（垂直）方向の中央寄せについては記載しません。
:::

## ブロック要素とインライン要素のおさらい

中央寄せしたい対象が**ブロック要素**なのか**インライン要素**[^1]なのかによって、CSSの指定方法は異なります。

ですので、まずはブロック要素とインライン要素の特徴や違いについて、ポイントを押さえておきましょう。

この辺りが理解できていないと、過去の私のように同じミスを繰り返すことになります。。

### ブロック要素

ブロック要素は、**HTMLを構成する基本となる要素**です。

`<main>`, `<h1>`, `<table>` , `<div>`, `<p>` などがブロック要素です。

:::note info
ブロック要素の主な特徴
- 改行される
- 要素が縦並びになる
- 中身の長さに関わらず、親要素の幅いっぱいに広がる
:::

これらの特徴を具体例で確認してみましょう。

わかりやすいように、`<p>` 部分にだけ背景色をつけています。

```html:index.html
 <div>
    <p>
        1つ目の段落です。これはブロック要素の説明用の文章です。
        ブロック要素はこのように一つのかたまりとなり
        親要素いっぱいに広がります。
    </p>
    <p> 2つ目の段落です。</p>
</div>
```

```css:style.css
p {
    background-color: greenyellow;
}
```

![block_sample.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/911578/c6e9e381-a583-b18c-9630-2e4b1b877d35.png)

:::note warn
文章の長さに関わらず `<p>` の領域が幅いっぱいに広がっている点を特に確認しておいてください。
:::

### インライン要素

インライン要素は、**文章の一部に対しスタイルやリンクなどの機能を適用**します。

`<span>`, `<a>`, `<strong>`などがインライン要素です。

:::note info
インライン要素の主な特徴
- 改行されない
- 要素が横並びになる
- 中身の長さで幅が決まる
- 行の一部にすぎないので余分な余白がない
:::

これらの特徴を具体例で確認してみましょう。

わかりやすいように、インライン要素である `<span>` 部分にだけ背景色をつけてみます。

```html:index.html
<p>pはブロック要素ですが、<span>spanはインライン要素</span>です。</p>
```

```css:style.css
span {
    background-color: greenyellow;
}
```

![inline_sample.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/911578/9d76120f-21eb-06bb-bb6b-fea0911fb6fd.png)


:::note warn
中身の文章の長さによって `<span>` の長さが決まっている点と、`<span>`タグの前後に余分な余白がない点を特に確認しておいてください。
:::

それでは、特徴がわかったところで、さっそく中央寄せしていきましょう。

なお、各要素についてもっと知りたい方は、末尾に詳細な表を載せていますので、そちらをご参照ください。

## インライン要素を中央寄せしたい場合

まずは**インライン要素**からです。

例として、インライン要素の一つである `<img>` を中央寄せしていきます。

青い背景の `<div>` 内にオレンジ色の画像 `<img>`があるとします。

```html:index.html
<div class="parent">
    <img class="child" src="./sample.png">
</div>
```

```css:style.css
.parent {
    height: 300px;
    width: 300px;
    background-color: blue;
}
```

初期配置は左寄せになっています。

![block_before.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/911578/c8bfbfa5-568b-c10e-a22c-eee4b5675b4e.png)

インライン要素の中央寄せには、`text-align:center;`を使います。

ただし、**指定する対象を間違えない**ように！

:::note warn
子要素ではなく**親要素に**指定してください！
:::

### :x: 誤った例 

```css:style.css
.child {
    text-align:center;
}
```

### :o: 正しい例

`text-align` はあくまで**親要素を元にして子要素をどこに配置するか**を決めるプロパティです。

なので、**中央寄せしたい要素自体ではなく、その親要素**に `text-align` を指定する必要があります。

```css:style.css
.parent {
    height: 300px;
    width: 300px;
    background-color: blue;
    text-align: center; /* 追加 */ 
}
```

無事に中央寄せできました。

![block_after.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/911578/3494a441-059f-247c-ee3d-28e0ad3349ad.png)

## ブロック要素を中央寄せしたい場合

次にブロック要素の中央寄せを見ていきます。

ブロック要素の中央寄せには、`margin: 0 auto;` または `display:inline-block;` を使用します。

まずは前者から。

### `margin` を利用して中央寄せする

`margin` は左右の余白を設定するプロパティです。

:::note info
`margin: 0 auto;` は、上下の余白を`0`、左右の余白を`auto`に設定しています。
`auto`とすると**自動的に余白を調節**してくれて中央寄せが実現できます。
:::

例として、ブロック要素の一つである`<div>`を中央寄せしていきます。

白い背景の`<body>`の中にピンク色の`<div>`があるとします。

```html:index.html
<body>
    <div class="block">
    </div>
</body>
```

```css:style.css
.block {
    width: 70px;
    height: 70px;
    background-color: pink;
}
```

初期配置は左寄せになっています。

![left_block.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/911578/55930637-0897-1717-c446-9ebebaccaa49.png)

### :o: 正しい例

`margin: 0 auto;`を指定すると中央寄せできます。

```css:style.css
.block {
    width: 70px;
    height: 70px;
    background-color: pink;
    margin: 0 auto; /* 追加 */
}
```

![center_block.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/911578/542fa72c-ed65-4087-fc93-e354e333d306.png)

### :x: 誤った例 

`width` を指定していないブロック要素は中央寄せできません。

```css:style.css
.block {
    /* widthが指定されていない */
    height: 70px;
    background-color: pink;
    margin: 0 auto;
}
```

なぜなら、ブロック要素は**幅を指定しなければ親要素の幅いっぱい**に広がるからです。

![full_width.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/911578/daa16904-36b4-268c-b6d1-10466deb0621.png)

親要素の幅いっぱいということは、**左右に余白なんてないので、当然中央寄せされない**ということになります。

:::note warn
インライン要素やインラインブロック要素も行の一部分にすぎず余分な`margin`がないため、`margin: 0 auto;`は効きません。
:::

### インラインブロック要素へ変更して中央寄せする

ブロック要素を中央寄せする方法として、ブロック要素を**インラインブロック要素へ変更する**という方法もあります。

そうすれば、インライン要素と同じく`text-align:center;`が使用できます。

:::note info
インラインブロック要素とは、インライン要素とブロック要素の両方の良いとこどりした要素です。

「**要素は横並びにしたいけど、width, height, margin, paddingも設定したい！**」といったときにインラインブロック要素に変更することが多いようです。
:::

インラインブロック要素への変更は、変更したい要素に`display:inline-block;` を指定するだけです。

例として、子要素の `<div>` をインラインブロック要素に変更し、中央寄せしていきます。

青い背景の `<div>` 内に、オレンジ背景の `<div>`があるとします。

```html:index.html
<div class="parent">
    <div class="child">
    </div>
</div>
```

```css:style.css
.parent {
    width: 100px;
    height: 100px;
    background-color: pink;
}
   
.child {
    width: 40px;
    height: 40px;
    background: blue;
}
```

初期配置は左寄せになっています。

![block_before.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/911578/f0f058a9-dd9d-44fc-87bd-e4e115e7c5d5.png)

中央寄せしたい子要素に`display:inline-block;`を指定します。

そして、インライン要素の章でやった通り、**親要素**に`text-align:center;`を指定します。

```css:style.css
.parent {
    width: 100px;
    height: 100px;
    background-color: pink;
    text-align: center; /* 追加 */
}
   
.child {
    width: 40px;
    height: 40px;
    background: blue;
    display: inline-block; /* 追加 */
}
```

中央寄せできました。

![block_after.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/911578/2e522d9d-25cf-48a1-50db-d09c35f66fd3.png)


## まとめ

親要素・子要素の種類ごとに、中央寄せする方法を表にしました。

![inline_block_table.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/911578/45a960ac-48f3-a3de-46af-81f3baa6d59e.png)

## おまけ：各要素の特徴

各要素の特徴を詳しくまとめた表を置いておきます。


|                    | インライン要素                                       | ブロック要素                     | インラインブロック要素                     | 
| ------------------ | ---------------------------------------------------- | -------------------------------- | ------------------------------------------ | 
| 用途               | 文章の一部に対しスタイルやリンクなどの機能を適用する | 文書の構造やレイアウトを決定する | インライン要素とブロック要素の良いところどり | 
| 要素の例                   | img, span, textarea, input, label, br etc...                | div, table, form, ul, p, h1~h6, header, main, section etc...   | ※ 初期値がインラインブロック要素である要素は存在しない |
| 指定方法 | `display: inline;`   | `display: block;` |`display: inline-block;`|
| 並び順             | 横並び                                               | 縦並び                           | 横並び                                    | 
| 前後の改行         | 無                                                   | 有                               | 無                                         | 
| widthの初期値      | 要素内の中身と同じ幅になる                     | 親要素の幅いっぱいに広がる       | 要素内の中身と同じ幅になる           | 
| heightの初期値     | 要素内の中身と同じ高さになる                      | 要素内の中身と同じ高さになる  | 要素内の中身と同じ高さになる            | 
| width/heightの指定 | 不可                                                 | 可                               | 可                                      | 
| marginの指定       | 左右のみ 可                                        | 上下左右 可                    | 上下左右 可                             | 
| paddingの指定      | 左右のみ 可（上下は他の要素に被る）                | 上下左右 可                    | 上下左右 可                            | 

:::note warn

imgはインライン要素ですが、特別に幅と高さの設定ができます
:::

## 参考

- [MDN Inline-level content](https://developer.mozilla.org/ja/docs/Glossary/Inline-level_content)
- [MDN Block-level content](https://developer.mozilla.org/ja/docs/Glossary/Block-level_content)
- [MDN CSS 基本ボックスモデル入門](https://developer.mozilla.org/ja/docs/Web/CSS/CSS_box_model/Introduction_to_the_CSS_box_model#%e3%83%9e%e3%83%bc%e3%82%b8%e3%83%b3%e9%a0%98%e5%9f%9f)
- [MDN text-align](https://developer.mozilla.org/ja/docs/Web/CSS/text-align)
- [HTMLの基本](https://www.htmq.com/htmlkihon/005.shtml)
- [CSS「text-align」を理解【効かない場合の対処方法】](https://web-camp.io/magazine/archives/27392)
- [【CSS】text-align:centerが効かない原因と対処法](https://web-engineer-wiki.com/html-css/text-align-solution/)
- [まだ違いに迷っているの？ブロック要素、インライン要素の違いを完全に理解しよう](https://reffect.co.jp/html/block_and_inline_understanding/)
- [【display】インラインブロック要素の性質と使い方](https://www.itra.co.jp/webmedia/what-is-inline-block.html)
- [margin: auto;の正体を暴く：CSSの中央揃えテクニック](https://itokoba.com/archives/976)

[^1]:インラインレベル要素、ブロックレベル要素ともいわれます