CSSはなぜ分かりにくいのか

ひょんなきっかけでCSSに触る羽目になり、ハマりまくった挙句トラウマになった方は結構多いのではないでしょうか。そのほとんどは、CSSの~~当たり前のことが当たり前のようにできない非合理的かつ旧態依然とした分かりにくい~~独特な仕様に起因します。
本記事では、今までCSSを書いてきてヘンだと思ったこと、ハマったポイントを思いつく限り書き連ねます。更に、今後同じ思いをする人がいないように、それぞれの項目に対応方法や解説も記します。
この記事を読んで「こんなの当たり前。知ってるよ」って思ったそこのあなた。すでに普通の人間ではありません。そんなあなたは歴としたCSS中毒患者です。

# 本文を読むにあたって

便宜上html4以前のブロック要素、インライン要素という言葉を用いています。
* ブロック要素→初期値がdisplay: blockの要素
* インライン要素→初期値がdisplay: inlineの要素
程度に解釈して読んでいただければと思います。


# センタリング

一番良く使うかつ、確実にハマるのがセンタリングです。ブロック要素orインライン要素、上下or左右で全くやり方が異なります。

*display: flex使えばいいじゃん？*

*Internet Explorerどうすんの？*

・・・😇

出ました、ブラウザ依存。これがCSSのツラいところです。ブラウザ依存については後述します。これから様々なセンタリングについて述べていきますが、本記事では敢えてdisplay: flexが使えない場合にフォーカスしていきます。

## ブロック要素の左右センタリング

これは定番のやつですね。ブロック要素に`text-align: center;`が効かない・・・というのを誰も一回は経験しているはず。`text-align: center;`がインライン要素にしか効かないからです。ブロック要素をセンタリングするには、センタリングさせたい要素に`margin-left: auto; margin-right: auto;`を指定します。センタリングするのに「center」という言葉が全く出てこないあたり流石CSSって感じです。以下に例を示します。

html

```html

<div>
  <p>test</p>
</div>

```

css

```css
/* 動かない */

div {
  text-align: center;
  background-color: #ccf;
}
p {
  width: 80%;
  background-color;
}

/* 動く */

div {
  background-color: #ccf;
}
p {
  width: 80%;
  margin-left: auto;
  margin-right: auto;
  background-color: #fcc;
}

```

出力結果

![](https://i.gyazo.com/2049b362f5e1e3e279b29861b8dff514.png)


## 1行のテキストの上下センタリング

1行テキストのセンタリングは、外側の要素の高さを同じ値をline-heightにすればよいです。
line-heightは名前の通り行の高さを指定するプロパティで、行間を指定する場合によく用いられます。

html

```html
<p>あいうえお</p>
```

css

```css
p {
  height: 50px;
  line-height: 50px;
  background-color: #fcc;
}
```

結果

![](https://i.gyazo.com/544676526567af6bda696f9584560a64.png)

## 複数行のテキストの上下センタリング

テキストの上下センタリングをするためにvertical-alignを使ってみたけどびくともしない。どうやるんだろう・・と思ったことがある方は多いはず。実は、vertical-alignはインライン要素や表のセル要素にしか定義できません。今回は、ブロック要素を`display: table-cell`で表のセルとして扱われるようにして、`vertical-align: middle`を使う方法を紹介します。


html

```html
<div class='container1'>
  <div class='container2'>
    あいうえお<br>
    かきくけこ
  </div>
</div>

```

css

```css
.container1 {
  width: 100%;
  display: table;
}

.container2 {
  width: 100%;
  display: table-cell;
  background-color: #fcc;
  height: 100px;
  vertical-align: middle;
}

```

結果

![](https://i.gyazo.com/d913b6292b7f2c9f33fe80c56466e723.png)

## `//`はコメントではない

CSSでのコメントは`/* */`です。気をつけましょう。

# ブラウザ依存

この世がChrome、Firefox、Safariといったブラウザだけなら平和なのですが、世の中そう甘くはありません。Android4以前のプリイントールブラウザ、Internet Explorerといった魑魅魍魎が2016年現在も跋扈しております。これらのブラウザはCSS3のプロパティをサポートしきれておらず、時々不具合を起こします。更に、Android4以前のプリイントールブラウザに至っては機種ごとに挙動が異なったりするので、完璧な動作確認は実質不可能です。

◯対応方法

各プロパティのブラウザ対応状況は http://caniuse.com/ で調べられます。CSS3のプロパティを使う場合は、まずサポート対象ブラウザで使用できるか調べましょう。もちろん、実装後の検証は欠かせません。

# ベンダープレフィックス

```css

/* transform */
-ms-transform: rotate(45deg);
-webkit-transform: rotate(45deg);
transform: rotate(45deg);

/* display: flex */
display: -ms-flex;
display: -webkit-flex;
display: flex;

```
ブラウザによる試験的実装のプロパティや設定値につけられるプレフィックスです。W3Cによる勧告前のプロパティをブラウザが先行実装した場合につけられることが多いです。CSS3のサポートが進むにつれてベンダープレフィックスは減っていますが、まだまだ必要なプロパティはあります。

◯対応方法

http://caniuse.com/ などで逐一調べるしかありません。

# 初期値

CSSは各要素にブラウザ依存の初期値が定義されています。そのため、予期せぬマージンやパディングが入るとがあります。

◯対応方法

CSSリセットと呼ばれるリセット用のスタイルを読み込むことで解決します。normalize.css(http://necolas.github.io/normalize.css/)などがあります。

# ネガティブマージン

マージンには負の値を指定することができます。これを使うと隣接要素にめり込むような形になります。
便利な場合もありますが、分かりにくいので多用するのは控えましょう。

# マージンは相殺される

隣接する要素にそれぞれマージンが設定されている場合、それらは相殺されます。それぞれの正負で挙動が異なります。

* 正と正&負と負・・・大きい方の値が隣接する要素の間隔になる
* 正と負・・・両者の値の合計が要素の間隔になる


https://www.w3.org/TR/CSS21/box.html#collapsing-margins

# 初期値ではパディングが幅・高さに含まれない

CSSでは初期値で`box-sizing: content-box;`が設定されています。
要素の幅・高さをwidth・heightで指定した場合、以下の図中の点線の領域のサイズになります。その結果、図中の実線に相当する要素の幅・高さは`width+padding`・`height+padding`となります。知っていれば何ともないですが、直感的でないと思う方もいると思います。

![image](https://qiita-image-store.s3.amazonaws.com/0/75424/1e08d768-34fa-e307-72f8-b558e6dc2d63.png)

◯対応方法

`box-sizing: border-box;`を指定しましょう。これで解決です。

# 文献
https://www.w3.org/Style/Examples/007/center.en.html

https://developer.mozilla.org/ja/docs/Glossary/Vendor_Prefix