#MSLearn の初心者向けペライチ web ページ制作チュートリアルやってみた (一切フレームワーク使わない)

リクエストをいただき、「[Microsoft の初心者向けチュートリアル](https://docs.microsoft.com/ja-jp/learn/modules/build-simple-website/?WT.mc_id=spatial-8948-machiy)をやってみた」記事です。([動画版](https://youtu.be/fkj1kcewlSk)もあります。)

https://docs.microsoft.com/ja-jp/learn/modules/build-simple-website/?WT.mc_id=spatial-8948-machiy

↓ 動画版

<iframe width="560" height="315" src="https://www.youtube.com/embed/fkj1kcewlSk" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>

内容：
一切のフレームワークを使わずに、生の JavaScript, CSS, HTML の 3 ファイルだけで、
ダークテーマとライトテーマを切り替えられる
ペライチ web ページを作る

![Animation8.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24609/a10fcf2a-d37f-7ef2-5883-6179bd3e16a7.gif)

見ての通りガチ初心者向けです。( web 制作で npm 一切叩かなかったの数年ぶり)

最近の web 制作は (JS フレームワークしかり UI コンポーネントしかり) リッチなフレームワーク様のお力をフルに使うことが当たり前になっているので
こうして素の JS/CSS だけで書くのは久しぶりなので新鮮で楽しかったです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24609/15f7d2bc-60e7-cc2f-2fc9-dd57b97eaf63.png)

書いたコード一覧（たった 3 ファイルです）

https://github.com/chomado/220614-simple-website

# 経緯

日本マイクロソフト公式 YouTube チャンネル「[くらでべ](https://youtu.be/fkj1kcewlSk)」（くらうどデベロッパーチャンネル）で

こちらの Microsoft Learn モジュール「[HTML、CSS、および JavaScript を使用してシンプルな Web サイトを構築する](https://docs.microsoft.com/ja-jp/learn/modules/build-simple-website/?WT.mc_id=spatial-8948-machiy)」チュートリアルを
ランスルーすることになりました。

[<img src = "https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24609/bd319f45-22ab-e3ee-aeb8-846edf156aeb.png">](https://docs.microsoft.com/ja-jp/learn/modules/build-simple-website/?WT.mc_id=spatial-8948-machiy)

https://youtu.be/fkj1kcewlSk

動画のほかにも文章媒体でも記録を残しておこうと思い、
記事を書くことにしました。

https://docs.microsoft.com/ja-jp/learn/modules/build-simple-website/?WT.mc_id=spatial-8948-machiy

ただ、このモジュールは「完全に初心者」を想定しているようで、かなり丁寧に書いてある（フォルダの中身を VSCode でどうやって開くかとか）ので、
この記事では要点と捕捉だけまとめて書いておこうと思います。

# キーワード

このチュートリアル中に触れられるキーワードを先に載せておきます（本文中に解説します）

CSS

* **`CSS 変数`** (CSS custom properties (variables))
* `セレクタ`、`プロパティ`、`値`
* `:root` 疑似クラスでカスタムプロパティを宣言することによりグローバル変数として使う方法

JavaScript

* JavaScript の **`厳格モード`** (strict mode)
* **`イベントハンドラー`** (event handler)

概念

* **`プログレッシブ エンハンスメント`** (progressive enhancement)
* **`関心の分離`** (separation of concerns)
* **`フォールトトレランス`** (Fault tolerance)

# もくじ

1. `はじめに` (Introduction)
1. `セットアップ - HTML, JS, CSS の 3 ファイルを作る` (Set up the structure of your web app)
1. `HTML 書く` (Add basic HTML to your web app)
1. `CSS でスタイルをいい感じにする` (Style your HTML with CSS)
1. `JavaScript でボタン押されたときのイベントハンドラを書く` (Add interactivity with JavaScript)


# 1 : Introduction - Scenario

ユニット１の「[はじめに - シナリオ](https://docs.microsoft.com/ja-jp/learn/modules/build-simple-website/1-introduction?WT.mc_id=spatial-8948-machiy)」を見ていきます。
ここでは完成形（このモジュールを完成したら何ができるか）を案内していますね。

これから作るペライチの static な web ページは、
ページ内のボタンでダークモードとライトモードを切り替えられる機能を持っています。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24609/34bae08a-1d0c-4385-b8b1-ba8a8a418642.png)

また、本文中に、役割ごとに HTML、CSS、および JavaScript ファイルに分割しましょうという言及があります。

1. `HTML` - コンテンツ（情報）
2. `CSS` - スタイリング（見栄えの装飾）
3. `JavaScript` - インタラクティブな動作,ロジック（振る舞い）

（HTML ファイルの中に CSS や JavaScript をべた書きしてひとつのファイルにまとめることも可能ですが、それはやらずに、ファイルを分けましょうという話。）

そこから、プログラムを関心（何をしたいのか）毎に分離された構成要素で構築しましょうという「[**関心の分離**](https://ja.wikipedia.org/wiki/%E9%96%A2%E5%BF%83%E3%81%AE%E5%88%86%E9%9B%A2)」(separation of concerns) についての説明が軽くあります。

たとえばひとつのクラスやファイルに複数の目的の記述があると暗黒になります。
依存関係の入り乱れたシステムにせず、それぞれのモジュールを疎結合に設計することが大切です。

# 2 : Set up the structure of your web app

ユニット２の「[演習 - Web アプリの構造を設定する](https://docs.microsoft.com/ja-jp/learn/modules/build-simple-website/2-project-structure?WT.mc_id=spatial-8948-machi)」を進めていきます。

作ったフォルダ「`simple-website`」の中に
以下のファイルを作ります

* index.html
* main.css
* app.js

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24609/3f9c110d-7175-110b-32c6-55cf696b12be.png)
(私は git init しているので .git 関係のファイルができています)

## Progressive enhancement

ここで、本文中に、
ファイルを HTML, CSS, JavaScript と分けることについて
**progressive enhancement** (プログレッシブ エンハンスメント) の説明が出てきます。


:::note
英和辞書で引いた時のそれぞれの単語の意味

[`progressive`](https://ejje.weblio.jp/content/Progressive)
1. 進歩的な
2. (段階的に)前進する，漸進(ぜんしん)する

[`enhancement`](https://ejje.weblio.jp/content/enhancement)
向上, 《機能などの》 拡張, 強化.

あわせると `progressive enhancement` とは「**漸進的（ぜんしんてき）な機能強化**」ということになります。
:::


プログレッシブ エンハンスメントは、**ブラウザ機能格差の解消についてでてくる実装手法** のひとつです。


:::note warn
ちょまぎょの一言

` (*ﾟ▽ﾟ* っ)З `「もう何年も前だけど、HTML5 や CSS3 の出始めのときに『HTML5/CSS3 サポートしないブラウザの対応どうしよう！？』って時代にすごく聞いたキーワードだった気がするわよ」
:::

「どのようなブラウザでも最低限の機能が動くように作る」のを前提にした「古いブラウザの人でも あなたのサイトを見られるようにする色んな手法」については

以下の三つがよく挙げられます：

* [グレイスフル デグラデーション](https://uxdaystokyo.com/articles/glossary/graceful-degradation/) (Graceful Degradation)
* [プログレッシブ エンハンスメント](https://uxdaystokyo.com/articles/glossary/progressive-enhancement/) (Progressive Enhancement)
* [リグレッシブ エンハンスメント](https://uxdaystokyo.com/articles/glossary/regressive-enhancement/) (Regressive Enhancement)

（個人的には、現在は、Progressive Enhancement よりは Graceful Degradation のほうが主流になっているような気がします）

![](https://www.endlessgain.com/wp-content/uploads/2017/10/progressive-enhancement-va-graceful-degradation.jpg)
(画像： [How Progressive Enhancement Can Future-proof Your Conversions](https://www.endlessgain.com/blog/how-progressive-enhancement-can-future-proof-your-conversions/) より)


### ファイルを分ける


今回このモジュールでは、上の 3 つの手法のうち、プログレッシブ エンハンスメント (Progressive Enhancement) に触れられています。

プログレッシブ エンハンスメントにおいて、3 層 (HTML, CSS, JS) を分離することはとても大切です。（最初に言及した「関心の分離」(separation of concerns) でも出てきましたね）

[モジュール原文](https://docs.microsoft.com/en-us/learn/modules/build-simple-website/2-project-structure?WT.mc_id=spatial-8948-machi)

> You could build a website by including all of your HTML, CSS styles, and JavaScript code within a single file. However, in this exercise you're using an HTML file for your content, a CSS file for your styling, and a JavaScript file for your interactivity.

和訳）HTML ファイルの中に CSS や JavaScript をべた書きしてひとつのファイルにまとめることもできます、が、我々は 3 つのファイルに別々に分けています。

1. `HTML` - コンテンツ（情報）
2. `CSS` - スタイリング（見栄えの装飾）
3. `JavaScript` - インタラクティブな動作（振る舞い）


![](https://i0.wp.com/alistapart.com/wp-content/uploads/2012/07/m-m.jpg?w=960&ssl=1)
(画像： [Understanding Progressive Enhancement](https://alistapart.com/article/understandingprogressiveenhancement/) より)

> The separation of content, styles, and logic is an example of **progressive enhancement**.

和訳）コンテンツ、スタイリング、ロジックに分けるのは、 **progressive enhancement** (プログレッシブエンハンスメント) の一例です。


> If JavaScript isn't enabled or supported by your customers, your CSS and HTML will still work. However, if CSS isn't supported by your customers, at least your HTML content will appear.

和訳）もし JavaScript がサポートされていないブラウザ（~~今どきそんなブラウザ使わないで欲しいけど~~）や無効化されている環境（これはしてる人はいるかもしれない）で あなたの web サイトを閲覧された場合でも、少なくとも HTML と CSS は動きます。
また、もし CSS がサポートされてない環境でも、少なくとも HTML のコンテンツは表示されます。

とのことで。

# 3 : Add basic HTML to your web app

ユニット３の「[演習 - Web アプリに基本的な HTML を追加する](https://docs.microsoft.com/ja-jp/learn/modules/build-simple-website/3-html-basics?WT.mc_id=spatial-8948-machiy)」を見ていきます。

## HTML 編集
VSCode で、index.html に「`html:5`」と入力し、Enter キーを押します。 
HTML5 テンプレートコードが追加されます。

![Animation3.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24609/fd8806c6-c2bb-953c-25e1-58aa986fdd86.gif)

## CSS 呼び出し

「link」と入力してから、Enter キーを押すと `<link rel="stylesheet" href="">` が入力されます。

![Animation4.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24609/a9e8f959-1829-de48-cef7-c5e669d4696d.gif)

ちなみに `href` 属性は読み込み先のソースの所在を指し示すもので、 "`hypertext reference`" の略です。
今回は `main.css` を読み込みたいので href の中身を main.css にします。
今全体はこうなっています

```html:index.html
<!DOCTYPE html>
<html lang="ja">
  <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>Simple website</title>
    <link rel="stylesheet" href="main.css">
  </head>
  <body>
  </body>
</html>
```
## web ブラウザで開く

index.html をブラウザで開いてみると現在はこうなっています

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24609/a8e0c716-ba48-13f1-3988-af2f18e5d62b.png)

## 開発者ツールを見てみる

ブラウザで `F12` で開発者ツールを見れます

![Animation5.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24609/5b5d6281-a15e-a293-69ab-a216f9ff2c5e.gif)

# 4 : Style your HTML with CSS

ページのスタイリングをする CSS の話に入ります。

https://docs.microsoft.com/ja-jp/learn/modules/build-simple-website/4-css-basics?WT.mc_id=spatial-8948-machiy

## CSS の書き方の基本

CSS を書く時の基本はこのフォーマットです

```css
セレクタ {
  プロパティ : 値
}
```

例えばこの main.css をこうしてみます

```css:main.css
body {
  font-family: monospace;
}
ul {
  font-family: helvetica;
}
li {
  list-style: circle;
}

.list {
  list-style: square;
}

#msg {
  font-family: monospace;
}
```

上の main.css には 5 つのセレクタが出てきます。

* 要素セレクタ：`body`, `ul`, `li`
* class セレクタ: `.list`
* ID セレクタ: `#msg`

main.css が反映されると、index.html はこうなります

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24609/ea376bd3-ab46-2039-288d-095e37148d18.png)

## ライト (明るい) テーマを追加する

```css:main.css
.light-theme {
  color: #000000;
  background: #00FF00;
}
```

```html:index.html
<body class="light-theme">
```

![](https://docs.microsoft.com/en-us/learn/windows/build-simple-website/media/light-theme.png)

## ダークテーマを追加する

### カスタムプロパティ（CSS 変数）を `:root` 擬似クラスで定義

**カスタムプロパティ**（**CSS 変数**）の宣言について。

カスタムプロパティ名はハイフン2つ (--) で始まるものにします。
また、`:root` に宣言することにより、html 全体で使用できるようになります。

それを `var(宣言したカスタムプロパティ名)` で呼び出すことができます。

```css:main.css。カスタムプロパティを宣言
:root {
  --green: #00FF00;
  --white: #FFFFFF;
  --black: #000000;
}
```

宣言したので呼び出します。

```css:main.css。呼び出し
.light-theme {
  --bg: var(--green);
  --fontColor: var(--black);
}
.dark-theme {
  --bg: var(--black);
  --fontColor: var(--green);
}
```

![Animation6.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24609/4432621b-8cc1-d508-5c73-f9fa8cd9c134.gif)


:::note 
ちょまぎょの一言

` (*ﾟ▽ﾟ* っ)З `「大昔の CSS は、こんな変数宣言とかできなかったのよね。とくにこの例にあるようにテーマカラーのカラーコードは何度も出てくるから、それを変更するときは（昔は）エディタで一括変換していたわ。でもこうして変数にできるのなら、変更時は宣言の値を変更すれば一括で変わってくれるから便利ね」
:::

:::note
別名『**CSS 変数**』について

` (*ﾟ▽ﾟ*; っ)З `「ちなみに『定数』じゃなくて『変数』なの？　最初に値を定義しておいて 他から参照しているだけだし、再代入をしないのなら定数じゃないの？」

🐟 たしかに、今回の例ではカスタムプロパティを定数のように扱っていますが、このカスタムプロパティは JavaScript を利用したら値を変更することも可能なので、『CSS 変数』で良いと思います

` (*ﾟ▽ﾟ* っ)З `「なるほど」
:::

ダークテーマとライトテーマの色設定が終わったので、
body セレクタの部分をこう書き換えます。

```css:main.css
body {
  background: var(--bg);
  color: var(--fontColor);
  font-family: helvetica;
}
```

そしてこの状態で html の body の class をダークテーマのものに書き換えて再度読み込みすると、見た目が変わります

```html:index.html
<body class="dark-theme">
```

![](https://docs.microsoft.com/ja-jp/learn/windows/build-simple-website/media/dark-theme.png)

# 5 : Add interactivity with JavaScript

JavaScript を使ってインタラクティブなサイトにしましょう

https://docs.microsoft.com/ja-jp/learn/modules/build-simple-website/5-javascript-basics?WT.mc_id=spatial-8948-machiy

## JavaScript 読み込み

body 内の最後の行で js ファイルを読み込みます

```html:index.html
<script src="app.js"></script>
```

## フォールトトレランス

**フォールトトレランス** (**Fault tolerance**) とは、

> システムや機器の一部が故障・停止しても、予備の系統に切り替えるなどして機能を保ち、正常に稼働させ続ける仕組みのこと
> (引用元：『[フォールトトレランス | IT用語辞典 | 大塚商会](https://www.otsuka-shokai.co.jp/words/fault-tolerance.html)』)

:::note
英和辞書で引いた時のそれぞれの単語の意味

[`fault`](https://ejje.weblio.jp/content/fault)
欠点, 過失, 障害

[`tolerance`](https://ejje.weblio.jp/content/tolerance)
我慢, 耐久力, 寛容, 耐性, 許容誤差

あわせると `Fault tolerance` とは「**障害耐性**」「**障害許容設計**」ということになります。
:::

`<noscript>` 要素を追加して、JavaScript が有効でない環境での閲覧時の対策をします。

```html:index.html
  <script src="app.js"></script>
  <noscript>
    You need to enable JavaScript to view the full site.
    このサイトをフルに閲覧するためには JavaScript を有効にする必要があります。
  </noscript>
</body>
```

## 厳格モードを設定する

 ES5 で導入された **厳格モード** (**Strict mode**) について。
これは[ドキュメント](https://docs.microsoft.com/ja-jp/learn/modules/build-simple-website/5-javascript-basics#set-strict-mode?WT.mc_id=spatial-8948-machiy)の言及がそのまま分かりやすいのでそのまま引用します。

> JavaScript は簡単に学習できるように設計されており、開発者が特定の間違いを犯しても許容されます。 
> たとえば、スペルに誤りのある変数を使用しても JavaScript はエラーをスローせず、代わりに新しいグローバル変数を作成します。 
> エラーが少ないのは JavaScript を学び始めるときは魅力的ですが、ブラウザーが最適化しにくく、デバッグが困難なコードになる可能性があります。


:::note
ちょまぎょの一言

`(*ﾟ▽ﾟ*; っ)З`「え、変数呼び出し時にスペルミスしてても、エラーにならず、さらに新しいグローバル変数を作成するの！？　こわ…」
:::


正直 strict モードじゃない JS は触りたくないです。（もっと言うと `"strict": true` した TypeScript のほうが好きです）

厳格モードを有効にするには、JS ファイルの最初にこれを書きましょう。

```js:main.js
'use strict';
```

:::note
私がこのモジュールやってて一番感心したのが、
ガチ初心者向けの内容ながら
ちゃんと JS を厳格モードでやることを指定していることでした
:::

厳格モードについてもっと知りたい方はこちら↓

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Strict_mode

## ボタンを追加する

ユーザーが Web ページでライト テーマとダーク テーマを切り替えることができるようにするためにボタンを追加します。

1. まず html でボタン (UI) `<button class="btn">Dark</button>` を追加してから
2. CSS でデザインを良い感じにして
3. 最後に JavaScript で、そのボタンが押された時の挙動（ロジック）を定義します。

### ボタン設置

```diff_html:index.html
<ul>
  <li class="list">Add visual styles</li>
  <li class="list">Add light and dark themes</li>
  <li>Enable switching the theme</li>
</ul>
+ <div>
+   <button class="btn">Dark</button>
+ </div>
<script src="app.js"></script>
```

`class="btn"` とクラス属性もしていますね。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24609/4c2915f0-1abf-53fe-38d1-43984ef50778.png)


### ボタンのデザイン調整

また、このボタンのデザインも CSS で定義します。
ダークモードのときとライトモードのときで色を変えるために、CSS 変数を使います

```diff_css:main.css ： 各モードでの色定義追加
.light-theme {
  --bg: var(--green);
  --fontColor: var(--black);
+ --btnBg: var(--black);
+ --btnFontColor: var(--white);
}

.dark-theme {
  --bg: var(--black);
  --fontColor: var(--green);
+ --btnBg: var(--white);
+ --btnFontColor: var(--black);
}
```

```css:main.css ： ボタンクラス追加
.btn {
  position: absolute;
  top: 20px;
  left: 250px;
  height: 50px;
  width: 50px;
  border-radius: 50%;
  border: none;
  color: var(--btnFontColor);
  background-color: var(--btnBg);
}
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24609/2c1c0391-6b26-b7c8-dbd6-3e5918934b83.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24609/77612c25-8a61-c1e3-d63c-8f5ecb403a01.png)

今はまだボタンを押しても何も起こりません。

## イベントハンドラーを追加

ボタンが選択されたときに何かが実行されるようにするには、
JavaScript でボタンが押されたとき用の **イベントハンドラー** (**event handler**) を定義します。

(handler: 英語で「扱う人」みたいな意味)

:::note
イベントハンドラ 【event handler】 とは：
> イベントハンドラとは、コンピュータプログラムで、特定の出来事（イベント）が発生した時に実行するよう定められた処理のこと。 
> 対象となるイベントの種類や条件と、処理内容をセットで記述する。
> 例えば「利用者がマウスでこのボタンをクリックしたらこの関数を実行する」といった形でプログラマが処理を記述する。
(引用元：『[イベントハンドラ（イベントリスナ）とは](https://e-words.jp/w/%E3%82%A4%E3%83%99%E3%83%B3%E3%83%88%E3%83%8F%E3%83%B3%E3%83%89%E3%83%A9.html)』)
:::

ボタンに対し、click イベントのイベントハンドラーを追加してみましょう。
このイベントハンドラー関数は、click イベントが発生したときに実行されます。

```js:app.js
const switcher = document.querySelector('.btn');
```

これで、あのページ内のボタンのオブジェクトを扱えるようになりました。
次に、そのボタン (switcher) が押されたとき ( = クリックイベントが発火したとき) の挙動を定義しましょう。

```js:app.js
switcher.addEventListener('click', function() {
    document.body.classList.toggle('light-theme');
    document.body.classList.toggle('dark-theme');
});
```

また、ボタンのテキストを押したときで変わるようにしましょう。（今は何度押しても「Dark」のままなので）

```js:app.js
const className = document.body.className;
if (className == "light-theme") {
  this.textContent = "Dark";
} else {
  this.textContent = "Light";
}
```

![Animation7.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24609/bf943915-d612-f395-31d7-226bd1b7fc89.gif)


## コンソールメッセージ

デバッグ用にコンソールにメッセージを出力してみましょう。
コンソールは web ブラウザで `F12` を押して開発者ツールを出すと見つかります。

app.js にコンソールに出力する記述をします


```diff_javascript:app.js
'use strict';
const switcher = document.querySelector('.btn');

switcher.addEventListener('click', function () {
  document.body.classList.toggle('light-theme');
  document.body.classList.toggle('dark-theme');

  const className = document.body.className;
  if (className == "light-theme") {
    this.textContent = "Dark";
  } else {
    this.textContent = "Light";
  }
+ console.log("現在のクラス名：" + className);
});
```

![Animation8.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24609/a10fcf2a-d37f-7ef2-5883-6179bd3e16a7.gif)

# まとめ

https://docs.microsoft.com/ja-jp/learn/modules/build-simple-website/7-summary?WT.mc_id=spatial-8948-machiy

# このページの短縮 URL

YouTube でこの記事を紹介するときに紹介しやすい URL が欲しくて、短縮 URL を取りました。

`https://aka.ms/simple-website-tutorial`

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24609/b6740e50-6497-f560-ea21-b1d1e6324967.png)


https://aka.ms/simple-website-tutorial