超マイナーなCSSヲタク知識を晒してみる：CSS displayプロパティ値の自動変換

これは[DMM.com #2 Advent Calendar 2017 - Qiita](https://qiita.com/advent-calendar/2017/dmm2) 23日目の記事です。
昨日は [@norinity1103](https://qiita.com/norinity1103) さんの [「パターン・ランゲージ」のワークショップを社内で実施した件](https://qiita.com/norinity1103/items/7541aef4fe52599541cf) でした。
カレンダーのURLはこちら
[DMM.com #1 Advent Calendar 2017 - Qiita](https://qiita.com/advent-calendar/2017/dmm)
[DMM.com #2 Advent Calendar 2017 - Qiita](https://qiita.com/advent-calendar/2017/dmm2)

# 自己紹介
はじめまして。DMM.com LaboのÉcouffesと申します。最近のマイブームは吉岡里帆のどんぎつねクリアファイルを30分毎に眺める事です。そのマイブームも、あれです、自動化したいです。はい。

# はじめに
今回 Advent Calendar 参加にあたり、当初は勢い余って**『超マイナーなCSSヲタク知識を晒してみる』**と宣言しました。
ヲタク知識たるもの、**実務に即役立つ有益な情報は積極的に除外**しなくてはなりません。とはいえ、どうせ晒すなら、何かしらCSSという言語の根幹に迫るヲタ情報でありたい。そこで今回は、**『W3Cの仕様書に記載されてはいるが、これまでコードレビューを重ねてきた私の経験上、世間的にあまり知られていないと思われるCSS知識』**を晒してみることにします。


# 対象読者
- CSSのdisplayプロパティの特性を理解されている方
- ブロックボックス、インラインボックスの特性を理解されている方


# displayプロパティ値の自動変換
早速結論から記載します。
**下記の条件をいずれか一つでも満たす場合は、当該DOM要素のdisplayプロパティ値は、inline系（inline, inline-block, inline-table, inline-flex, inline-gridなど）にはならない**：

1. ルート要素
- floatプロパティの値が、none以外
- positionプロパティの値が、absolute と fixed
- flex item（displayプロパティ値に **flex** が適用された要素の子要素）
- grid item（displayプロパティ値に **gird** が適用された要素の子要素）

### 実証方法
chromeのDevToolsを使って確かめてみてください。
1 についてはhtml要素に対して、inline系のdisplayプロパティ値を適用し、computed styleにて確認してみてください。

<img width="663" alt="スクリーンショット 2017-12-20 0.07.18.png" src="https://qiita-image-store.s3.amazonaws.com/0/55612/56134405-2da9-fde4-4588-ee7e2e1b9c49.png">


または、下記のJSコードでも確認可能です。

```js
const html = document.getElementsByTagName('html')[0];
html.style.display = 'inline';
// インラインスタイルのdisplayプロパティ値にsetしたはずの'inline'ではなく、'block' を返す
document.defaultView.getComputedStyle(html)['display'];
```

どうでしょうか？ 
CSSでは、

```css
display: inline;
```

が宣言されていても、computed styleではinline以外のプロパティに自動変換されていることが確認できます。

次は、2をDevToolsにて確認してみます。
下記のように、span要素があります。displayプロパティは初期値の**inline**が適用されています。
<img width="672" alt="スクリーンショット 2017-12-20 0.14.04.png" src="https://qiita-image-store.s3.amazonaws.com/0/55612/da4c9370-5b9f-14c2-64ee-74f9e043cf3b.png">

こちらへ、

```css
float: left;
```

を適用してみると：
<img width="670" alt="スクリーンショット 2017-12-20 0.14.32.png" src="https://qiita-image-store.s3.amazonaws.com/0/55612/ea297bb2-5f4f-33c6-ca69-0e623eca715f.png">

displayプロパティの値が、自動的にinlineからblockに変換されていることが確認できます。

ただし、ここで注意が必要なのは、全てのinline系のプロパティ値がblockへ変換されるわけではありません。元々のdisplayプロパティ値の特性を活かしたまま、inline特性のみが削除されるように自動変換されます。
具体的には、下記のようになります：


| declaration value| computed value    |
|:-----------------|-------------------|
| inline           | block             |
| inline-block     | block             |
| inline-table     | table             |
| inline-flex      | flex              |
| inline-grid      | grid              |

実際に確認してみます：

先ずは

```css
display: inline-flex;
```

というinline系のdisplayプロパティ値を適用してみます。

<img width="673" alt="スクリーンショット 2017-12-20 0.15.38.png" src="https://qiita-image-store.s3.amazonaws.com/0/55612/e9a19825-f4d6-6631-d11a-88644723456b.png">

次に、floatを適用してみると、displayプロパティ値が、flexへ自動変換されたのが確認できます：
<img width="669" alt="スクリーンショット 2017-12-20 0.16.02.png" src="https://qiita-image-store.s3.amazonaws.com/0/55612/bd366023-35b7-4f5b-5c74-583fc0d9d33f.png">

３〜5についての実証も上記と同じ方法で可能なため、詳細は割愛します。

### 一次資料（W3C）
上記の各項目についてはW3C公式文書に記載有：
- 1~３について、[Cascading Style Sheets Level 2 Revision 2 (CSS 2.2) Specification > 9-7 Relationships between 'display', 'position', and 'float'](https://www.w3.org/TR/CSS22/visuren.html#dis-pos-flo)
- 4について、[CSS Flexible Box Layout Module Level 1 > 4. Flex Items](https://www.w3.org/TR/css-flexbox-1/#flex-items)
- 5について、[CSS Grid Layout Module Level 1 > 6.1. Grid Item Display
](https://www.w3.org/TR/css-grid-1/#grid-item-display)

また、displayプロパティ値が生成する『ボックス』という、より根源的な視点から、inline値へ自動変換が行われる点についての詳しい説明文書は下記に記載有：
[CSS Display Module Level 3 > 2.7. Automatic Box Type Transformations](https://www.w3.org/TR/css-display-3/#transformations)


# この知識の活用どころ
~~特にありません。~~
強いてあげれば、自身がCSSを書く際や、他者のコードレビューの際に活用できます。例えば、float・絶対配置と、inline-blockが同じ宣言ブロック内に入っている場合：

```css
.hoge {
    float: left;
    display: inline-block;
    vertical-align: middle;
    ...
}
```

上記のようなCSSルールセットは、散見されることが多いかと思います。
この場合は、

```css
    display: inline-block;
    vertical-align: middle;
```

上記CSS宣言群はcomputed時には、inlineとしての機能は自動的に失われますので、まるごと削除可能です。
vertical-alignプロパティも、displayプロパティのinline値が生成する**インラインボックス**のみに有効なプロパティのため、不要になります。


# 最後に
HTMLやCSSは様々な職種の人が使用している言語ですが、W3CやWHATWGの公式文書までに目を通している人は割と少ないのでは無いのでしょうか？
普段何気無く使用しているHTMLやCSSという言語、もし少しでも疑問に感じる点があったら、公式文書に目を通す事で新たな発見があるかもしれません。




# 参考
- https://www.w3.org/TR/CSS22/visuren.html#dis-pos-flo
- https://www.w3.org/TR/css-flexbox-1/#flex-items
- https://www.w3.org/TR/css-grid-1/#grid-item-display
- https://www.w3.org/TR/css-display-3/#transformations