エンジニア向け！CSSレイアウト講座＆用途別に選べる横並び・中央寄せのまとめ

私の会社では、HTMLやCSSまわりはデザイナーやコーダー、マークアップエンジニア、フロントエンドエンジニアが作るのですが、
たまに工数の関係でバックエンドエンジニアやサーバーサイドエンジニアに直接HTML/CSS側を修正してもらうことがあります。
今回は、その方々向けによく質問に上がるようなレイアウトの基礎部分を教えるために展開した資料を再度まとめました。

※HTML/CSSのソースが書いてある部分は、codepenなどで実際にソースを表示しながら説明したので
　同じように確認してもらえると分かりやすいとおもいます。

# ながれ

- HTMLのブロック要素とインライン要素
- positionプロパティ
- 横並びのCSS
- 中央寄せのCSS（テキスト）
- 中央寄せのCSS（ブロック）
- まとめ

# HTMLのブロック要素とインライン要素

CSSの前に、少しだけHTMLについて説明をしたいと思います。
HTMLには、ブロック要素とインライン要素というものがあります。

## ブロックレベル要素

文書の骨組みとなる要素です（例えば見出しや段落など）。

これらは特にスタイルを指定しない場合、幅を画面いっぱいに取り、前後が改行されます。
 簡単に言ってしまうならば、ブロックを作り出します。 

ブロック要素の中には大体なんでも入れられます。

### たとえば

- div
- h1～h6
- table
- ul
- ol
- p

などなど

## インライン要素

インライン要素は、ブロック要素の内容として使われるもので、文書の構造を構成するというより、ブロック要素内の特定の部分になんらかの役割や機能を持たせる要素です。

たとえば、ある語句に対してハイパーリンク機能を与える アンカー要素、 特定の語句を強調する要素などです。

インライン要素の中にインライン要素を入れることはできますが、ブロック要素を入れることはできません。

### たとえば

- a
- br
- em
- span
- img
- input
- strong

などなど

図で見るとこんなかんじ

![image.png](https://qiita-image-store.s3.amazonaws.com/0/146963/1d345fa4-e1d3-3a8f-68c9-228b11dc5d4f.png)
（参照：[ブロックタイプレベルとインラインレベルについて](https://nest-online.jp/articles/282)）

ブロック要素とインライン要素というのはタグごとに決められていますが、
CSSでこれを変えることができます。
それが

**display** プロパティ

まずはざっと種類

|種類|説明文|
|:-----------|:------------|
|inline|インラインボックス|
|block|ブロックボックス|
|none|要素が表示されず、レイアウトに影響を与えない|
|list-item|li要素のようにマーカーがつくリスト要素になる|
|inline-block|インライン要素のように表示がされるけれどもブロック要素のように幅や高さが指定できる。|
|table-cell|テーブルのセル（td）のような表示|

＜図で見るとこんなかんじ＞

![image.png](https://qiita-image-store.s3.amazonaws.com/0/146963/d10b4076-b068-a47a-1844-32074603c29a.png)

（参照：[イメージで学ぶ！CSSのdisplayの使い方を総まとめ](https://saruwakakun.com/html-css/basic/display)）

### どういう時に使うの？？

…たとえば

- **リンクのタップ範囲を広くしたい！**
- **特定の要素を最初は非表示にしたい！**
- **横並びにしたいけどブロック要素にしたい！**

などなど

このあたりは理解してますよという方も多いと思います。

では、なぜブロックとインラインの話を最初にしたのかというと、
この要素の違いによって効いてくれるCSSが異なるからです。

どんなときに使うかはまたのちほど事例をもとに紹介します。

そして、もうひとつ重要なプロパティがあるので先にそちらを紹介します。

# positionプロパティ

positionとはものすごくざっくりというと「要素の位置を決める」ためのプロパティです。

|種類|説明文|
|:-----------|:------------|
|static|初期値。あんまり使いません。|
|relative|現在の位置を基準に相対的な位置を決める|
|absolute|親要素を基準に絶対的な位置を決める。親要素にstatic以外が指定されていなければ、ウインドウの左上が基準になります。|
|fixed|画面のきまった位置に固定する。スクロールしても位置が固定されたままとなります。|


## positionとセットで覚えたい～top left right bottom～

要素の位置を指定することができます。
基本的にpositionとセットで使います。（初期値のstaticのときには指定できないからです！）

![image.png](https://qiita-image-store.s3.amazonaws.com/0/146963/ec5e7033-7d05-78af-a7ec-92c0871286c0.png)
（参照：[イメージで学ぶ！CSSのpositionプロパティの使い方](https://saruwakakun.com/html-css/basic/relative-absolute-fixed)）

こんなかんじで位置が指定できます。

ここで、positionの説明にもどります。


![image.png](https://qiita-image-store.s3.amazonaws.com/0/146963/5dce6c13-930a-9e3b-6574-d5db39e84038.png)
（参照：[イメージで学ぶ！CSSのpositionプロパティの使い方](https://saruwakakun.com/html-css/basic/relative-absolute-fixed)）

```html
<p>指定なし</p>
<p class="position">位置を指定します</p>
```

```css
p {
  background-color: #ccc;
}

.position{
  position: relative;
  top: 10px;
  left: 10px;
}
```

このように、元々の表示位置を相対的に位置指定ができます。

------------

![image.png](https://qiita-image-store.s3.amazonaws.com/0/146963/dfa2c067-f8dc-29f7-a36f-a9f0e2703d91.png)
（参照：[イメージで学ぶ！CSSのpositionプロパティの使い方](https://saruwakakun.com/html-css/basic/relative-absolute-fixed)）

この「絶対的な位置」というのは、要素がどんな形であろうと、間に他の要素や余白が入っていようと、その位置に配置してくれるということ意味します。
ちなみに親要素に何も指定されていなかったら、ウインドウの左上を起点として、親要素にstatic以外が指定されていれば親要素からの絶対配置になります。

```html
<div class="sample">
  <p>うえに要素を置くよ</p>
</div>
<div class="box">
  <p>指定なし</p>
  <p class="position">位置を指定します</p>
</div>
```

```css
p {
  background-color: #ccc;
  margin: 0;
}

.position {
  position: absolute;
  top: 0;
  left: 0;
  background-color: pink;
}

.sample {
  height: 100px;
  background-color: orange;
}

.box {
  position: relative;
}
```

↑の場合だと、「.box」の左上を基点として「位置を指定します」のピンクのボックスが配置されるので、
「指定なし」の上にピンクのボックスが重なります。

---

![image.png](https://qiita-image-store.s3.amazonaws.com/0/146963/ca5a9f5b-0d38-2c04-0a6a-ad0a700edbaf.png)
（参照：[イメージで学ぶ！CSSのpositionプロパティの使い方](https://saruwakakun.com/html-css/basic/relative-absolute-fixed)）

スマホサイトによくある追従ボタンが大体これです。

位置調整をするときにはpositionプロパティが重要になるので、主にrelativeとabsoluteは覚えておいてください！

それでは、早速出現頻度の高いレイアウトを例にCSSの指定方法を紹介していきます。

# 横並びのCSS

## 例


![image.png](https://qiita-image-store.s3.amazonaws.com/0/146963/aa22f957-b2e8-2e9e-d5a9-be2223179851.png)

こんなかんじのレイアウトを作るとします。

ベースとなるHTMLとCSS

```html
<div class="container">
  <div class="thumbnail-container">
    <img class="thumbnail" src="img/service-step-1.png" width="76">
  </div>
  <div class="media-body">
    引っ越しの見積もりに必要な情報を入力してください。24時間いつでも無料でご利用いただけます。
  </div>
</div>
```

```css
.container {
  width: 100%;
  background-color: #ccc;
  border: 1px solid #000;
}
```

わかりやすくするために、要素を囲っているcontainerには線と背景を指定しています。

## floatを使う

まずはおなじみfloat。
floatプロパティとは、指定した要素を左寄せまたは右寄せにします。

|種類|説明文|
|:-----------|:------------|
|left|指定した要素を左寄せにして、次の要素は右側に回り込む|
|right|指定した要素を右寄せにして、次の要素は左側に回り込む|
|none|指定しない|

```css
.container {
  width: 100%;
  background-color: #ccc;
  border: 1px solid #000;
}

.thumbnail-container {
  float: left;
}

.media-body {
  float: left;
  margin-left: 10px;
}

.clear {
  clear: both;
}

.clearfix:after {
  content: "";
  clear: both;
  display: block;
  height: 0
}
```

floatさせた次の要素を回り込ませないようにしたいときは、
**clear**プロパティで、floatを解除すると回り込まずに下に表示されます。

### 注意！

floatは、要素を浮かせて左右どちらかに寄せる、というプロパティなので、
親要素から見たときに高さを保つことが出来ません。
そんなときには、親要素にclearfixをつければ解決！（どのサイトのCSSにも居ます）

```html
<div class="container clearfix">
  <div class="thumbnail-container">
    <img class="thumbnail" src="img/service-step-1.png" width="76">
  </div>
  <div class="media-body">
    引っ越しの見積もりに必要な情報を入力してください。24時間いつでも無料でご利用いただけます。
  </div>
</div>
```

こんなかんじ。

ちなみに、テキスト部分に何も指定をしないと長いテキストは画像の下に回り込みます。
画像の下に回り込むのいやだ！ってときは、テキストに`overflow: auto;`を指定すると下に回り込まなくなります。

overflowプロパティも便利です。（スクロールとかできるよ）

### inline-blockをつかう

さきほど上でも説明したdisplay要素で、ブロック要素をインライン要素のような表示形式に変えることで横並びにします。


```css
.container {
  width: 100%;
  background-color: #ccc;
  border: 1px solid #000;
}

.thumbnail-container {
  display: inline-block;
  vertical-align: middle;
}

.media-body {
  display: inline-block;
}
```

inlineではなくinline-blockです。

上にも書いたとおり、inline-blockは
> インライン要素のように表示がされるけれどもブロック要素のように幅や高さが指定できる。

という要素になります。

インラインでも出来ないことはないのですが、ブロック要素にしないとレイアウトの調整がしづらいのでinline-blockにします。


ここで気になる突然出てきた**vertical-align**。
気になるとは思いますが後から説明するので先に次のパターンにいきます。

## table-cellをつかう

inline-blockと同じように、displayプロパティを使用しテーブルのレイアウトを作ります。

```css
.container {
  width: 100%;
  background-color: #ccc;
  border: 1px solid #000;
  display: table; /* 親要素をテーブルに */
}

.thumbnail-container {
  display: table-cell; /* 子要素をテーブルのセルにする */
  width: 86px;
}

.media-body {
  display: table-cell; /* 子要素をテーブルのセルにする */
  vertical-align: middle;
}
```

親要素をtableにして、子要素をテーブルのセルにすることで横並びにします。
ちなみに、テーブルにするので横幅を勝手に調整してしまいます。
横幅が決まっている場合はなるべく指定します。（%でもOK）
そしてここにも出てきたvertical-align。

## flexboxをつかう

まだまだPCでは崩れまくるflexプロパティは横並びを簡単に作れます。

```css
.container {
  width: 100%;
  background-color: #ccc;
  border: 1px solid #000;
  display: flex;
}

.media-body {
  margin-left: 10px;
}
```

flexもdisplayプロパティで指定ができます。
このflexは、今まで出た例のように子要素に指定するのではなく、親要素に指定します。
親要素にflexを指定すると、子要素が横並びになります。
（ほんとは縦並びにすることも出来たりする便利なやつです。flexbox）

ただこいつらはPCだとIEの古いバージョンが未対応。
SPもAndroid4系だと崩れるので今のところ業務ではかなり使い所を選びます。

いろんなレイアウトが出来るプロパティなので、よかったらこれでも見てすごいなって思ってくれると嬉しいです。

Instagramの各パーツをflexboxで組み立てる
http://qiita.com/nezurika/items/2b358f02e27d9b1085fb

以上が、よく使う横並びのCSSたちです。
floatも使いますが、スマホサイトだとtable-cellを使うことが多いです。（また下で便利な使い方を説明します）

# 中央寄せのCSS（テキスト）

ただ単にテキストを左右中央にしたいときは`text-align` で出来ます。
左右はできても、横並びにした時、中身を上下中央にしたいときありませんか？？？？

そんなときに使うのが

## vertical-align


散々出てきたプロパティですが、こいつを使うときの注意点が有ります。

**インライン要素またはtable-cellにしか効かない**

たとえばこんなデザインがあるとします。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/146963/3010c2cd-4dff-00d4-3d27-b7b2f0ad0990.png)


```html
<ul>
  <li>総合ランキング</li>
  <li>単身ランキング</li>
  <li>家族ランキング</li>
  <li>その他ランキング</li>
</ul>
```

```css
ul {
  list-style-type: none;
  display: table;
  width: 500px;
  height: 100px;
  table-layout: fixed;
}

li {
  background-color: #faf9f6;
  display: table-cell;
  border-top: 1px solid #e8e2d6;
  border-bottom: 1px solid #e8e2d6;
  border-left: 1px solid #e8e2d6;
  text-align: center;
  font-size: 14px;
  vertical-align: middle; /* 中央指定 */
}

li:last-child {
  border-right: 1px solid #e8e2d6;
}
```

この場合だと、table-cellで横並びにしているので、子要素にvertical-alignを指定して上下位置を決めることが出来ます。

### ちなみに

`table-layout: fixed` を`display: table;` が指定してある要素に追加すると、子要素の横幅が固定になります。
指定しないと勝手に横幅決められてしまいます。

`last-child` や `first-child` などの疑似要素で、上の場合だと最初のリストや最後のリストのみにCSSをあてることができます。

`nth-child(2)` だと2つ目、`nth-child(2n)` だと2の倍数、 `nth-child(2n+1)` だと2の倍数＋1、などなど。

Qiitaのテーブルみたいに奇数の列と偶数の列で色を変えたいときなどに使えます。

## line-heightをつかう

高さが決まっている場合のみ使えます。

```css
ul {
  list-style-type: none;
  display: table;
  width: 500px;
  height: 100px;
  table-layout: fixed;
}

li {
  background-color: #faf9f6;
  display: table-cell;
  border-top: 1px solid #e8e2d6;
  border-bottom: 1px solid #e8e2d6;
  border-left: 1px solid #e8e2d6;
  text-align: center;
  font-size: 14px;
  line-height: 100px; /* heightと同じサイズを指定 */
}

li:last-child {
  border-right: 1px solid #e8e2d6;
}
```

行の高さを指定する`line-height` に要素の高さと同じ値を入れると真ん中になります。


# 中央寄せのCSS（ブロック）

テキストの中央寄せよりもブロックの中央寄せがしたい、そんなときのほうが多いですよね。
ということで、ブロックの中央寄せをいくつか紹介したいと思います。

ここに箱が有ります。

```html
<div class="container">
  はこ
</div>
```

```css
.container {
  width: 100px;
  height: 100px;
  background-color: #ccc;
  border: 1px solid #000;
}
```

## margin:auto;をつかう（左右のみ）

```css
.container {
  margin-left: auto;
  margin-right: auto;
}
```

左右のmarginにautoを指定します。
autoを指定することで、横にあった隙間を左右均等に分配してくれるので真ん中に寄ります。

### 注意！

autoを使うときは、その要素の`width` を指定していないと真ん中に寄りません！
つまり、横幅を指定できる要素しか無理なのでインライン要素も無理です！

このやり方が一番使うことが多いです。

ちなみに、上下には効きません。不便。

## left: 50%;で調整する

```css
.container {
  width: 100px;
  height: 100px;
  background-color: #ccc;
  border: 1px solid #000;
  position: relative;
  left: 50%;
  margin-left: -50px;
}
```

左右の場合、手っ取り早く、横から50%の位置に置きます。
そして、要素の横幅の半分をmarginで左に戻します。

### 注意！

marginと同じくwidth指定をしないと中央寄せにはできません。
`left` `right` といった位置指定のプロパティは、`position` プロパティを指定していないと効きません。

## transformをつかう

```css
.container {
  width: 100px;
  height: 100px;
  background-color: #ccc;
  border: 1px solid #000;
  position: relative;
  left: 50%;
  transform: translateX(-50%);
}
```

`transform` プロパティをつかうと移動ができます。
上のようにleftで50%動かしたら、要素の横幅の50%を左に戻して中央寄せにします。
ちなみに、中央寄せにしたい要素の親要素に高さが指定してある場合、
topの追加と、 `transform: translateY(-50%);` にしたら上下中央真ん中になります！
`transform: translate(-50%, -50%)` でX軸とY軸両方指定できます。

## absoluteが使えるときの中央寄せ

`position: absolute` が使えるときはこれでも寄せられます。

```css
.container {
  width: 100px;
  height: 100px;
  background-color: #ccc;
  border: 1px solid #000;
  position: absolute;
  top: 0;
  left: 0;
  bottom: 0;
  right: 0;
  margin: auto;
}
```

## 横幅が可変なときの中央寄せ

横幅が可変だけど中央寄せにしたい、そんなときありますよね。

そういうときはこちら

```html
<div class="outer">
  <div class="container">
    はこ
  </div>
</div>
```

```css
.outer {
  text-align: center;
}

.container {
  height: 100px;
  width: 100px;
  background-color: #ccc;
  border: 1px solid #000;
  display: inline-block;
}
```

親要素に`text-align: center` を指定して、子要素に`display: inline-block;` を指定します。
実は`text-align`は中身がインライン要素のものにしか効きません。
そのためinline-blockにして効くようにしてます。

私は、ページネーションとかヘッダーメニューとか、リストの横並びで中央寄せにしたいときはこれをよく使います。

---

たくさん出てきたけどそれぞれどうやって使い分けたらいいの？と思うかと思います。
前後やページ全体のレイアウトによって異なるのですが、

たとえば横並びをしたい場合、
タブみたいなデザインのときはtable-cellを使えば横並びかつ簡単に子要素を等倍にできたり
inline-blockなら親要素にcenterを指定すれば中央寄せにできたりするのでそれらを選びます。

中央寄せも、下にくる要素関係無しでとにかく真ん中！というときはabsoluteを使うパターン、
要素の高さを保ったままでいたいときはrelativeを使うパターンを、などなど

ほかのレイアウトを見つつ選びます。

# まとめ

CSSはまだまだ増え続けているのでデバイスやブラウザごとに使えないタグもありますが、
便利なタグがどんどん増えてきました:hugging:
すばらしいですね:clap:

今回はレイアウトを主に紹介しましたが、CSSはできることがたくさんあります。
その分選択肢が多く難しいですが、綺麗にうまくできたときは嬉しいです:v:

以上です。ありがとうございました:grin: