VSCodeで生成できるHTMLテンプレートの中身、理解してます？

# 概要
VSCodeでHTMLファイルを書く際に、よくこんなテンプレートを生成して使うじゃないですか。
```html:こんなの
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body></body>
</html>
```
これがすっごく便利で、あとはbodyの中身を書いたり必要なscriptを持ってきたりすればOKなのですが、テンプレートで生成される要素について理解を深める機会が無くなってしまい、いわゆる「おまじない」的な扱いにしちゃってたりしませんか？

そんなに難しい内容じゃないのですが、html要素やhead要素の中身を理解しておくのは大事なことだと思うので、少し紐解いていければと思い、この記事を書いてます。

実際自分も少し「おまじない」的な扱いをしちゃってた頃があったので（小声）

# 各コードを見てみる

## html要素
最初にhtml要素を見てみましょうか。
```html:html要素
<html lang="en">
...
</html>
```
https://developer.mozilla.org/en-US/docs/Web/HTML/Element/html

html要素は、<strong>HTMLドキュメントのルート要素となる要素</strong>です。

html要素の子要素として、<strong>１つのhead要素と１つのbody要素</strong>が入ります。<strong>head要素を先に記述し、body要素は後に記述する</strong>必要があります。

```html:NG（子要素にbody要素がない）
<html lang="en">
  <head>
    <title>NG</title>
  </head>
</html>
```

```html:NG（子要素にhead要素がない）
<html lang="en">
  <body>NGです～～～</body>
</html>
```

```html:NG（子要素の順番が正しくない）
<html lang="en">
  <body>惜しいけどダメ</body>
  <head>
    <title>NG</title>
  </head>
</html>
```

これ自体がルート要素となるため、<strong>親要素が存在することは許可されていません</strong>。
```html:NG（html要素に親要素は存在してはいけない）
<div>
  <html lang="en">
  </html>
</div>
```

html要素の属性として、グローバル属性を指定することができます。

https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes

特に見かけるのは`lang`属性でしょうか。今回テンプレートにはlang属性が記載されているので、そちらを見ていきます。

### lang属性
lang属性はHTMLのグローバル属性で、各要素に特定の言語を指定することできます。
ほとんどの場合langはhtml要素に付けると思いますが、これ自体はグローバル属性でどこでも使えるので、一部の要素に対して別の言語を指定する、といった使い方も可能です。

```html:それぞれの要素ごとに言語を指定できる
<p lang="ja">この段落は日本語だよー。</p>
<p lang="en">This paragraph is English dayo-.</p>
```

lang属性は、実はデフォルト値がunknownであり、基本的に何かしらの言語を指定することが望ましいとされています。
lang属性を指定する場合、以下のコードをハイフンで繋げたものであることが求められます。

#### 言語サブタグ
必須要素で、`en`や`ja`など、基本となる言語コードを表します。
#### スクリプトサブタグ
任意要素で、`Brai`や`Kana`など、指定した言語サブタグの中でも、特定の書記体系を表します。
例えば、日本語のカタカナでWebページを作るなら`ja-Kana`とします。
ただ、ほとんどの場合必要ないです。（
そもそもこれの存在を知らんかった。
）
#### 地域サブタグ
任意要素で、`US`や`ES`など、特定の場所で話されている方言の言語コードを表します。
例えば英語もアメリカ英語やイギリス英語なんて言うと思うのですが、アメリカ英語を表したいのであれば`en-US`と表します。

これらの言語コードについて、以下のサイトから調べることができるようです。

https://r12a.github.io/app-subtags/


結構書いたのですが、日本語で書いてるこの記事を読まれている方は、おそらく日本語のサイトをメインで作ると思うので、基本`ja`を指定することになるかと思います。
とはいえ、大事なのは「<strong>このサイト・テキストはどの言語を使える人に伝えたいんだ？</strong>」という点なので、場合によって使い分けましょ～。

## head要素
```html:head要素
<head>
...
</head>
```

https://developer.mozilla.org/en-US/docs/Web/HTML/Element/head

head要素は、ページのタイトルや文字コードなどのメタデータコンテンツを記載する場所です。

head要素は子要素として<strong>０個以上のメタコンテンツ（meta要素やscript要素・link要素など）と１つのtitle要素</strong>を含みます。また、head要素の子要素が画面上に表示されることはありません。

head要素の親要素は<strong>html要素のみ</strong>許可しています。

```html:NG（親要素がhtmlではない）
<div>
  <head>
    <title>NG</title>
  </head>
</div>
```

## title要素
```html:title要素
<title>Document</title>
```

https://developer.mozilla.org/en-US/docs/Web/HTML/Element/title

ページのタイトルを示す要素です。

title要素は子要素として<strong>テキストのみ</strong>を含みます。

```html:NG（テキスト以外の要素は許可されていません）
<title>
  <h1>タイトルにHeadingは入れられないよ！</h1>
</title>
```

title要素の親要素はhead要素のみを許可しています。

```html:NG（親要素がhead要素じゃない）
<body>
  <title>親要素はheadでお願いします</title>
</body>
```

title要素を設定する意味として、「<strong>ページの目的を説明する</strong>」というものがあります。実際に検索エンジンで検索結果を表示する際、このtitle要素に書かれたテキストが強調されて表示されることになるので、SEO的な観点でもとても重要な要素です。

title要素に設定するテキストとして、<strong>通常１語や２語程度の短い文章は避けるべきで、そのページの内容を簡潔に表せるような程よい長さの文章が望ましい</strong>とされています。検索エンジンは通常55 ~ 60文字程度までタイトルを表示するとのことなので、その辺りを目安にタイトルの設定を行うのが良さそうです。

## meta要素
```html:meta要素
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
```

https://developer.mozilla.org/en-US/docs/Web/HTML/Element/meta

meta要素では、HTMLを構成する他の要素では表現できないようなメタデータを扱います。

meta要素は<strong>子要素を一切許可しておらず、終了タグも使わない</strong>ので、属性を使って設定を行います。

親要素については、<strong>設定する属性によって許可されるものが変化</strong>します。

設定できるメタデータは複数あり、今回はテンプレートを例に３つ見てみます。

### charset属性
```html:charset属性
<meta charset="UTF-8">
```
charset属性では、それを記述したHTMLソースの文字エンコーディングを表します。
ここでは文字のエンコーディング方法を設定できますが、実は<strong>この属性には必ず「UTF-8」（大文字小文字は問わない）を指定しなくてはいけない</strong>というルールがあります。

HTML5では、UTF-8（Unicode）のみを唯一有効な文字コードとしており、それ以外のエンコーディングを指定することは避けるべきとされています。
一応ASCIIやShift-JISを指定することはできますが、これらを残しているのは<strong>過去のHTMLソースとの互換性を維持するため</strong>であり、これから新しく作成するものについては必ずUTF-8を指定しましょう。

また、charset属性に関しては<strong>HTMLソースの先頭から1024バイト以内に記述し、文字エンコーディングの宣言を行う</strong>必要があります。忘れないためにも、head要素の一番初めの子要素として文字エンコーディングの宣言を行うと良いでしょう。

この属性が設定されておらず、文字エンコーディングの指定が確認できない場合、ユーザーエージェントはいくつかの方法で推測し、HTMLソースを処理します。
この際に誤判定が起きた場合（UTF-8で書いた文書がShift-JISとして解釈されてしまうなど）、文字化けを引き起こす原因となってしまいます。セキュリティの脆弱性に繋がることもあり、制作者には<strong>文字エンコーディングの指定を確実に行うこと</strong>が求められます。


### http-equiv属性
```html:http-equiv属性
<meta http-equiv="X-UA-Compatible" content="IE=edge">
```
http-equiv属性では、HTTPレスポンスヘッダと同様に情報を指定することができます。
この属性は列挙型であり、以下の情報を設定できます。
|  項目  |  説明  |
| ---- | ---- |
|  content-type  |  文字エンコーディングが設定可能。<br>古い書き方で、現在はcharsetを使うのが一般的。  |
|  content-security-policy  |  ページ上でユーザーエージェントが参照できるデータの制限が可能<br/>XSS攻撃への対策が可能  |
|  default-style  |  優先して反映するスタイルシートのリンク  |
|  refresh  |  ページがリロード・リダイレクトされるまでの秒数<br>リダイレクトの場合、リダイレクト先を指定可能 |
|  X-UA-Compatible  |  IE(Internet Explorer)に対して互換性を与える  |

今回テンプレートから生成されたものの場合、IE（Internet Explorer）というブラウザに対して互換性を与えています。

...が、IEは昨年の6月時点でサポートを終了しており（正確にはまだ使えるらしいですが）、互換性を与える必要はほとんどないと思います。
むしろそれ以外で設定できる項目について知っておいた方が良さそうです。リダイレクトなんかは404ページなどで使えそうですよね！

これらの設定方法について、詳しくは[コチラ](https://www.w3schools.com/tags/att_meta_http_equiv.asp)を見ていただけると良いかと思います。

https://www.w3schools.com/tags/att_meta_http_equiv.asp

### viewport属性
```html:viewport属性
<meta name="viewport" content="width=device-width, initial-scale=1.0">
```

viewport属性では、主にモバイルブラウザに対しての表示制御に関する情報を設定できます。

設定できる値として、以下のものがあります。

| 項目  |  説明  |
| ---- | ---- |
|  width  |  ページの横幅  |
|  height  |  ページの縦幅  |
|  initial-scale  |  ページが読み込まれた際の画面の表示倍率（デフォルト：１）  |
|  minimum-scale  |  許可する最小の表示倍率  |
|  maximum-scale  |  許可する最大の表示倍率  |
|  user-scalable  |  ページ上でズームインorズームアウトを許可するか（デフォルト：１）  |
|  interactive-widget |  <strong>Android上のGoogle Chromeで</strong><br>スクリーン上にキーボードを表示する際の動作を指定  |

今回テンプレートで生成されたものの場合、「ページの横幅をデバイスの横幅と同じとし、読み込まれた際の画面のズームレベルはデフォルトにする」という意味のようです。

また、interactive-widgetについてはここ最近追加された項目であり、Chrome108のリリースに伴った動作の変更に対応するためとのことです。
もしAndroidファーストで制作を行われているようであれば、interactive-widgetの設定についても理解しておくと良さそうです。

こちらのサイトの説明が分かりやすそうでしたので、詳しく知りたい方は是非。

https://developer.chrome.com/blog/viewport-resize-behavior/

## body要素

```html:body要素
<body>
  ...
</body>
```

https://developer.mozilla.org/en-US/docs/Web/HTML/Element/body

body要素では、そのページのコンテンツを表し、ここに記述したコンテンツが実際に画面上に表示されます。

親要素として<strong>html要素のみ許可しており、必ず2番目の子要素であることが必要</strong>です。

```html:NG（親要素がhtmlではない）
<div>
  <body>親要素はhtmlでお願いします</body>
</div>
```

子要素は<strong>フローコンテンツ</strong>と呼ばれるものが許可されており、<strong>一部のメタデータコンテンツを除いたほぼ全ての要素が許可されている</strong>と思ってもらって大丈夫だと思います。

# おわりに
調べてみると色々知らないことがあるんだな～～と思いました。
特に、viewportのinteractive-widgetについては存在すら知らなかったので、今回記事にする過程で知ることができて良かったです。

暗黙の了解として扱っていた部分について見直してみる、という機会を作るのも良いものですね。

...HTMLを完全に理解できる日は、まだまだ来なさそうです。