【デザイナーでもわかる】ブラウザがデザインを表示するまでに何をしてるのか

# デザイナーでもわかるブラウザの構成について
某企業のデザイナーをしています。ブラウザなどには全く理解がないもののデザインが崩れる要因からブラウザについて学習をしました。
専門用語の理解もない状態だったので自分がつまづいた点も、自分なりにまとめてデザイナーでも理解できるような記事を書いていきたいと思います。

### この記事を読んだらどうなるのか？
簡潔ではありますが、HTMLを読み込んでどのように画面に表示されるのか一連の流れが分かるようになる。

## 目次
| 項番 | 目次|
|:----:|:-------------|
| 1 | [1. ブラウザの主な機能](#ブラウザの主な機能) |
| 2 | [2. レンダリングエンジンとは](#レンダリングエンジンとは) |
| 3 | [3. HTMLの解析](#HTMLの解析) |
| 4 | [4. CSSの解析](#CSSの解析) |
| 5 | [5. レンダーツリーの構築](#レンダーツリーの構築)|
| 6 | [6. レイアウト](#レイアウト)|
| 7 | [7. ペインティング](#ペインティング)|
| 8 | [8. 最後に](#最後に)|

# ブラウザの主な機能
ブラウザの主な機能はユーザーの選択したウェブリソースをサーバーに要求してブラウザウィンドウに表示することです。
基本的にリソースは、HTMLドキュメントですが、PDFや画像などもリソースに含まれています。

今回は、サーバーに要求した後ブラウザに表示されるまでを説明していきたいと思います。
実はブラウザに表示させるには、**レンダリングエンジン**というものが役割を担っています。
では、レンダリングエンジンとは何でしょうか、確認していきましょう。

# レンダリングエンジンとは？
ブラウザはHTMLやCSSを読み込みソースを解釈して、画面に表示させます。
その**HTMLやCSSを解釈して画面に表示させる部分がレンダリングエンジン**と言います。

レンダリングエンジンのレンダリングとは何かというと、元となる情報を整形して表示してくれる事です。
例えば、このようなHTMLがあります。
`<ul><li>A</li>
 <li>B</li>
 <li>C</li>
 <li>D</li><ul>
`
実際にブラウザで見るとこうなりますよね。
・A
・B
・C
・D
このように元となるHTMLの情報を、あらかじめ決められたルールで整形して表示してくれていますよね。
要するに**レンダリングエンジンは、元となるHTMLやCSSなどの情報を元に整形して画面に表示してくれる役割。**と理解してください。


#### レンダリングエンジンの種類
ちなみにレンダリングエンジンは複数の種類があります。

1.**Trident**
IEに使われているレンダリングエンジン

2.**Gecko**
FireFoxに使われているレンダリングエンジン(一部Servoが使用されている)
	
3.**Blink**
Google Chromeに使われているレンダリングエンジン

4.**Webkit**
Safariに使用されているレンダリングエンジン

5.**EdgeHTML**
現世代のMicrosoft Edgeに使用されているレンダリングエンジン

デザイナーに関係する**表示崩れは、ブラウザによってレンダリングエンジンが違うことが要因**です。
レンダリングエンジンが違うということは、、HTMLやCSSの解釈の仕方も違います。そのためchromeではいいけどIEではデザインが崩れているといったことが起きます。（~~デザイナーにこれを伝えたかっただけです・・・~~）
逆に言えば、どのブラウザも同じレンダリングエンジンを使用していると、基本的に同じ見た目になる。（カスタマイズされていれば見た目は変わる可能性もある）


#### レンダリングエンジンのメインフロー
本題はここからですが、画面に表示するまでのメインフローについてお話させていただきます。
レンダリングエンジンはまず、要求したドキュメントのコンテンツを取得します。
※ドキュメントとは、書類や文書のこと
レンダリング エンジンのその後の基本的なフローはこちらです。
![flow.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/381381/9ca426d8-4574-9c17-76e7-bf074be3ead3.png)
>引用元：https://www.html5rocks.com/ja/tutorials/internals/howbrowserswork/#The_browsers_we_will_talk_about

左から順に解説していきます。
1.レンダリングエンジンがHTMLを解析して、DOMツリーを構築します。
2.CSSファイルとstyle要素内のデータを解析して、スタイル情報とDOMの情報を組み合わせてレンダーツリーを作成します。
3.レンダーツリーが作成されると、レイアウトに進みます。ここで画面に表示される正確な座標が各ノードに割り当てられます。
4.次に描画が始まります。レンダーツリーが走査され各ノードが描画されます。

**ぶっちゃけ今はわからなくてもいいです。**ふーんこんな流れでブラウザに表示されるのかと思っててください。この手順に沿ってこれから説明していきます。

手順に出てきたノードとは何でしょうか？
**dom（ツリー）などのノードは、木構造の節のことで、それそのものとして独立しているが（親子など）関係を作れる**ものです。
例えば、簡単なネットワークがあった場合の構成図はこうなります。
【パソコン】ー【ルーター】ー【サーバー】
これをもっと簡潔に書くと、
![ノード.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/381381/fbf24e99-1db8-204f-fc41-1c39e128a876.jpeg)
のように点と線で表せれます。（パソコン ー ルーター ー サーバー）
今回の場合は、パソコン・ルーター・サーバーは独立しているものですが、ネットワークとしては関係が作られるのでこのようなツリーで表現できます。


▼webkitのメインフロー（図１）
大枠のメインフローについてお話しましたが、もちろんレンダリングエンジンの種類によってメインフローも異なります。
参考程度にwebkitのメインフローはこちらになります。
![Attachment.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/381381/979095e7-43b6-9857-4410-288e8a1de85d.jpeg)


# HTMLの解析
>1.レンダリングエンジンがHTMLを解析して、DOMツリーを構築します。

1のようにDOMツリーを構築するには、HTMLパーサーが必要になります。
**HTMLパーサーとは、HTMLマークアップを解析してDOMツリーにする**ことです。
※ちなみにパーサーとは文書構文を分析して解析ツリーを構築する役割を担っています。

#### HTMLの文法の定義
HTMLの語彙と構文はW3C組織によって作成された仕様で定義されています。
HTMLの定義はDTD形式と言います。

DTDとは、「HTMLファイルはこんな構造になっている」とルールを定めているファイルです。
例えば、「このお魚は100円です。」と書いたときに100円を強調したいと思いました。
文章ファイルに`<strong>``</strong>`を囲えば強調扱いになるというルールを設けます。
そこで文章ファイルを
「このお魚は`<strong>`100円`</strong>`です」
と書き換えれば「このお魚は**100円**です」と強調されますよね。
要するに**DTDとはHTMLファイルなどの構造を示す時の書き方のルール**ということです。

もう少しデザイナーに分かりやすくいうとHTMLファイルを作成するときに
`<!DOCTYPE html>`をファイルの先頭に書きますが、こちらの意味は(Document Type Definition、DTD、文書型宣言)です。

どうゆうことかと言うと、HTMLのバージョンごとに使用できる要素（タグ）や属性とそれらの配置ルールが定められています。DOCTYPE宣言は、その文書がHTMLのどのバージョンで作成されているかを宣言するものです。
その文書で利用するHTMLのバージョンを宣言するのでその文書内では、宣言したHTMLのバージョンで定められているルールを守ってソースを記述しないといけません。


#### DOM（Document Object Model）
ブラウザはHTMLを読み込む時にHTMLの個々の要素をそれぞれ対応するDOM要素に変換します。
文字列ををW3Cで規定されている個々のトークンに変換して、オブジェクトに変換します。

例えば、このようなコードがあります。
`<html>
　<head>
　　 <title>お魚料理</title>
　</head>
　<body>
　　<h1>お魚レシピ</h1>
　　<p>鯖<small>一匹</small></p>
　</body>  
</html>
`

文書に含まれる要素や属性、テキストなどがオブジェクトに変換されます。
![object.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/381381/2a652250-30a1-cd90-bc27-9e3436db5986.jpeg)

これらの作成されたオブジェクトをHTMLで定義されたタグごとの関連性に基づきツリー型のデータ構造になります。（DOMツリー）

![DOM構造.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/381381/a54e1d91-7f7d-61ab-23f5-b749814e3d64.jpeg)
このような形でHTMLファイルがHTMLパーサーを通してDOMツリーとして表現しています。


余談ですが、オブジェクトに変換される時は、以下の4つに解析されます。
要素ノード：HTMLのタグ（今回で言うheadとか）
テキストノード：タグではないテキスト（今回で言う青色のお魚レシピなど）
属性ノード：hrefとかimgのsrcとか
ドキュメントノード：HTMLファイル全体のこと（今回のdocumentの部分）


# CSSの解析
CSS仕様では、CSSの字句および構文の文法が定義されています。
各CSSファイルはStyleSheetオブジェクトに解析され、各オブジェクトにはCSSルールが含まれています。
CSSルールオブジェクトには、セレクターオブジェクトと宣言オブジェクト、CSS文法に対応する他のオブジェクトが含まれています。

![cssRules.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/381381/e2df0b7d-72b8-44a5-0f93-f964e3e25449.png)


#### スクリプトとスタイルシートの処理順序
パーサーがscriptタグに到達するとすぐにスクリプトタグの解析が実行されます。
ドキュメントの解析はスクリプトが実行されるまで停止します。
スクリプトが外部にある場合でもリソースをネットワークから取得する必要があり、これも同期的に行われリソースが取得されるまで解析は停止します。
※同期的とは、スレッドが特定のオブジェクトに対する処理の権利（ロックと呼ぶ）を獲得したら、それが解除されるまでは他のスレッドがアクセスできなくなること。

しかし、WebkitとFireFoxはこの最適化を行います。
スクリプトが実行中に、別のスレッドがドキュメントの残りを解析してネットワークからロードする必要のある他のリソースを見つけてロードします。リソースを並列接続にロードでき全体的な速度が向上する。
これらは、外部スクリプト、スタイルシート、画像などの外部ソースへの参照のみを解析します。

`※スレッドとは、処理の単位です。
上記で「別のスレッドが残りを解析〜」と言うのは、複数のことを同時に処理していると理解してください。`

一方スタイルシートは、DOMツリーを変更しないため、スタイルシートを待ってドキュメントの解析を停止する理由はありません。
ただし、ドキュメントの解析段階でスタイル情報を要求するスクリプトは存在します。
スタイルがロードや解析されていない場合は、全てのスクリプトをブロックすることや、スタイルシートに影響を受ける可能性がある特定のスタイルプロパティにアクセスしようとする場合はスクリプトをブロックします。



# レンダーツリーの構築
DOMツリーとstyle Rulesを組み合わせたものがレンダーツリーに含まれます。
レンダーツリーは各表示要素のレイアウト計算するために使用され、コンテンツを正しい順序でペイントできるようにすることです。
**表示要素なので、非表示のものはレンダーツリーに挿入されません。
例えばhead要素や非表示のものになります。**
Visibility: hiddenとdisplay:noneは異なっていて、前者は要素は非表示ですが、レイアウト上のスペースは確保されます。
後者はレンダリングツリーから完全に削除されるので要素はレイアウトにも含まれません。
下記の図がとてもわかりやいので参考にしてください。

![イメージ.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/381381/b7c38a54-df3f-e1fb-108b-8fa7e923a7eb.jpeg)


**レンダーツリーを構築するには各レンダーオブジェクトのプロパティを計算する必要**があります。
これは各要素のスタイルプロパティを計算することによって行われます。
※スタイルプロパティとは、様々なスタイルシート、インラインスタイル要素などが含まれています。
※インラインスタイル要素とはHTMLにCSSコードを書き込んでいるもの

これらの計算を行い、DOMツリーとstyle Rulesを組み合わせてレンダーツリーを構成します。
これで2が完成しました。
> 2.CSSファイルとstyle要素内のデータを解析して、スタイル情報とDOMの情報を組み合わせてレンダーツリーを作成します。


# レイアウト
レンダリングツリーが正しく構築してくれたら、レイアウト段階に進みます。
**レンダーツリーでは、どこに描画するのか場所やサイズが決まっていません、端末のビューポート内での正確な位置とサイズを特定する役割がレイアウトです。**
※ビューポートとは、ブラウザ毎の表示幅のこと。

よくわからないので例を見てみましょう
下記のようなコードがあります。
`<!DOCTYPE html>
<html>
  <head>
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <title>Critial Path: Hello world!</title>
  </head>
  <body>
    <div style="width: 50%">
      <div style="width: 50%">Hello world!</div>
    </div>
  </body>
</html>`

ページに2つのdivがあり、1つ目のdivはビューポートの50%に設定して、子のdivは親の50%に設定しています。
つまり1つ目のdivはビューポートの50%で子のdivはビューポートの25%ということです。
レイアウト処理の出力は、ビューポート内の各要素の正確な位置とサイズを取り組んだ「ボックスモデル」で、全ての相対的な測定値を画面上の絶対的なピクセルに変換する処理などが行われています。
![ビューポート.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/381381/6c9d613a-64a5-6de5-2b01-7f5937d33869.jpeg)


ボックスモデルとは、テキストや画像などの内容領域を持っており、その周辺にパディングやボーダー、マージンの順に周辺領域を持っているということ。
![ボックスモデル.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/381381/6b079275-44f6-4526-1238-d94c69a24cab.jpeg)


# ペインティング
**ペインティングとは表示されるノード、そのノードの計算済みのスタイル、形状がわかったのでこの情報をもとにレンダーツリー内の各ノードを画面上の実際のピクセルに変換を行います。**
ここはみなさんが目にする部分なので理解しやすいかなと思います。

ペインティングはブラウザの処理量が多いため、時間がかかります。
レンダーツリーからペイントまでに必要な時間は、ドキュメントのサイズ、適用されるスタイル、端末によっても異なります。
ドキュメントが大きいほど必要な処理も増え、スタイルが複雑なほどペインティングに時間がかかります。
これらの処理を終えるとページがビューポートに表示されます。
<img width="381" alt="スクリーンショット 2020-01-26 13.25.05.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/381381/16f30e51-1b6f-10f7-0296-2d94dc69cd02.png">


以上でブラウザに表示されるまでの処理については終了になります。

## 最後に
最初よりも少し詳しく簡単にブラウザが表示されるまでに以下のことを行なっています。

1.HTMLマークアップを処理してDOMツリーを構築
2,CSSマークアップを処理してStyle Rulesを構築
3.DOMとStyle Rulesを組み合わせて、レンダーツリーを構成
4.レンダーツリーをもとにレイアウトを実行して各ノードの計算をする
5.各ノードを画面にペイントする。