1
4

More than 1 year has passed since last update.

MicrosoftのWeb開発教材を使ってみた ③テラリウム構築 【HTML・CSS基礎/DOM操作/クロージャ】

Last updated at Posted at 2022-02-09

はじめに

「Web Development For Beginners」というMicrosoftがGithubに公開している教材についての記事です。

教材の紹介・選んだ理由など

この教材を選んだ理由

https://github.com/microsoft/Web-Dev-For-Beginners

  • HTML/CSS/JavaScriptを触れるいい感じの教材が欲しかった
    • そこそこのボリュームがあり、作りながら学べるタイプの教材
    • 基礎的なトピックが一通り網羅されている
  • 質が高そう
    • なにせあのMicrosoftなので、きっと良いものでしょう。
  • 題材が面白そう
    • 軽く調べた感じだとチュートリアルでよくある題材として「TODOアプリ」「クイズアプリ」などがあるみたいですが、どれもどう実装するのか想像がついてしまって、余り興味がわきませんでした。
    • しかしこの教材は「テラリウム」「タイピングゲーム」「ブラウザ拡張機能」「スペースゲーム」「銀行プロジェクト」と、面白そうなトピックが並んでいます。

+α 実際に取り組んで感じたこと

  • 提供されるリファレンス・参考サイトの質が高い
    • 一例はFlexbox Froggy。🐸 を並べながら flexbox の扱いについて学べるサイトです。超わかりやすいです。

https://flexboxfroggy.com/#ja

  • 「アクセシビリティ」「ブラウザがどう動くのか」といった知識も学べる
    • 絶対やるべきだけど後回しにしがちなトピックも結構ガッツリ触れます。
    • かゆいところに手が届く感じ。
  • 多分、英語全くわからなくてもなんとかなる
    • ほとんどのレッスンは translationsというフォルダに日本語訳があります。
    • 最悪全部Deeplに突っ込めばなんとかなります。
  • Edge推しがすごい
    • Microsoftの教材なので当然ですが、デモでは基本Edgeが使われます。
  • スケッチノートがわかりやすい
    • 一部レッスンは最初にスケッチノートというイラストがあるのですが、それがすごくわかりやすいです。それに可愛い。
    • 扱うトピックについてイラストで視覚的に示してくれるので、どんな内容をやるのかざっくり把握してからレッスンに入ることが出来ます。

image.png

microsoft/Web-Dev-For-Beginners/tree/main/1-getting-started-lessons/3-accessibility より

教材の概要

各レッスンに以下の要素が含まれます。

  • スケッチノート(オプション)
    • レッスンの概要がわかりやすくまとまったイラスト
  • 補足のビデオ(オプション)
  • レッスン前の小テスト
    • 簡単なテスト
  • ステップバイステップなレッスン
  • 知識のチェック
  • レッスン後の小テスト
    • 簡単なテスト
  • チャレンジ
  • 副読本(サイト)
  • 復習と自己学習
  • 課題

チャレンジ〜は調べ物や課題をこなします。
課題については必要だと思ったものだけやりました。

教材の構成

  1. getting-started-lessons(はじめに)
    1. プログラミング言語と開発ツール
    2. アクセシビリティ
    3. Githubの基礎
  2. js-basics(JavaScript基礎)
    1. データ型
    2. 関数とメソッド
    3. 分岐処理
    4. ループ
  3. terrarium(テラリウム構築)
    1. HTMLイントロ
    2. CSSイントロ
    3. DOM操作とクロージャ
  4. typing-game(タイピングゲーム)
    1. タイピングゲームを作る(イベント管理)
  5. browser-extension(ブラウザ拡張機能)
    1. ブラウザについて
    2. API呼び出し、ローカルストレージの利用
    3. バックグラウンドタスクとパフォーマンス
  6. space-game(スペースシューティングゲーム)
    1. イントロ(Pub-Subパターン)
    2. キャンバス
    3. モーションの追加
    4. レーザー追加、衝突検出
    5. スコアの保存
    6. 終了と再起動
  7. bank-project(架空の銀行プロジェクト)
    1. WebアプリのHTMLテンプレートとルート
    2. ログインと登録フォームの構築
    3. データの取得と利用方法
    4. 状態管理の概念

取り組む際に気をつけたこと

  • コピペ/写経にならないようにする
    • サンプルコードと実装の解説が一緒になっているので、理解したつもりになってコピペしがちです。
    • まず一通り目を通してから、なるべく自分の頭で考えて実装するようにしました。
  • 全部完璧にやろうとしない
    • 「12週間、24レッスンのカリキュラム」と銘打たれているように、出される課題や副教材を全てこなそうと思うとかなりボリュームがあります。
      • そのため、現時点で必要だと思うカリキュラムにのみ取り組みました。


〜②JavaScript基礎まで【導入/アクセシビリティ/JavaScript の基礎】
③テラリウム構築 【HTML・CSS基礎/DOM操作/クロージャ】 本記事
④タイピングゲーム 【JavaScriptのイベント処理】
⑤-1ブラウザ拡張機能 【ブラウザの仕組み/拡張機能作成の導入】
⑤-2ブラウザ拡張機能 【API/LocalStorage/BackGround/Performance】
⑥スペースシューティングゲーム 【ゲーム開発の基礎/Pub-Sub/Canvas/衝突検出】
⑦-1銀行プロジェクト【SPA//HTMLフォーム】
⑦-2銀行プロジェクト【ログイン/データ管理/状態管理】


記事の目的

  • 学習のアウトプット
  • 教材を使ってみたところかなり良かったので、その紹介

注意点

自身の学習のアウトプットがメインなので、理解できているところ(他言語と共通の箇所など)は省いています。
また、課題やtipsについても結構省きます。
この教材に興味を持った方はぜひご自分で取り組んでみてください。

3-Terrarium

ドラッグ&ドロップで操作可能なテラリウムを作っていきます。

学習の目的

  • レイアウトの構築を中心に、テラリウムを作成するための HTMLを構築する。
  • レスポンシブ対応などCSSの基本を中心に、オンラインテラリウムのスタイルを整えるCSSを構築する。
  • テラリウムをドラッグ&ドロップのインターフェイスとして機能させるための JavaScriptを構築する。

https://github.com/microsoft/Web-Dev-For-Beginners/raw/main/3-terrarium/images/screenshot_gray.png

完成イメージ https://github.com/microsoft/Web-Dev-For-Beginners/tree/main/3-terrarium より

HTML入門

HTMLの基礎について学んでいきます。

Webページをスケルトンだとすると、HTML/CSS/JavaScriptはそれぞれ以下のようになります。

  • HTMLは骨格
  • CSSはおしゃれ
  • JavaScript は命を吹き込む(動かす)

この例えわかりやすいですね。

基本的なHTML

  1. <!DOCTYPE html> を最初に入れる
  2. <html> の開き/閉じタグで全体を挟む
  3. <head>metadate(Webページそのものの情報)を書く
    <head>
        <title>Welcome to my Virtual Terrarium</title>
        <meta charset="utf-8" />
        <meta http-equiv="X-UA-Compatible" content="IE=edge" />
        <meta name="viewport" content="width=device-width, initial-scale=1" />
    </head>

4.<body> にHTML要素を書いていく。

  • それぞれのタグは通常<p>Hello</p>のように、開閉タグがある。
  • 閉じタグが不要な要素の代表例に <img> がある。
    • 例 : <img class="plant" alt="plant" src="/images/hoge.png"
    • これはブラウザが画像を表示するのに src 以外の情報を必要としないから。
    • alt には画像の内容を示す適切な情報を含める。
  • 装飾用のタグとして主に使われるのは <div><span>
    • <div> はブロック要素
    • <span> はインライン要素
    • ざっくり言うとブロックは改行あり、インラインは改行なしの要素

5.セマンティックなHTMLを書く

非推奨のHTML

このリストに非推奨のHTMLが載っています。これらは使うべきではないそうです。

ですが、そもそもなぜ非推奨になるのでしょうか?少し調べてみました。
Why Do Some HTML Elements Become Deprecated?

  • HTMLで構造を書くこと/CSSでスタイルを書くことが分離されてきたことで、それらがひとまとめになったようなHTMLは廃止されてきた。
  • CSS普及以前はテーブルを使ったレイアウトがよく使われていたが、アクセシビリティ、パフォーマンス、入れ子関係が複雑になりやすいなどの理由から使われなくなった。
    • 弊社の出退勤管理システム(結構古め)を見てみたら確かにテーブルレイアウトでした。そもそも使いにくいから更新してほしい

副教材

CSS入門

CSSは、以下のような役割を持つ。

  • Webサイトの見栄えを良くする
  • レスポンシブウェブデザインを作成する
  • アニメーションをつける

基本

ul {
    font-family: helvetica;
}
  • ul : セレクタ
    • タグ ul bodyのようにタグ名を書く。
    • id #から始め、IDを書く。idは固有の値。
    • class .から始め、クラス名を書く。
  • font-family : プロパティ
    • スタイリングの対象
  • helvetica : 値
    • どのようにスタイリングするか指定する
  • CSSの読み込み
    • HTMLの<head><link rel="stylesheet" href="./style.css">を含める。
    • HTMLファイルに直接CSSを書く事もでき、その場合外部のCSSを読み込むよりも優先度が高い。

継承

<body>
    <h1></h1>
</body>

上のような場合を考えると、

  • <h1>セレクタでスタイルを指定しなかった場合、<h1><body>のスタイルを継承する。
  • <h1>で指定した場合は<h1>のスタイルが優先される。

要するに、より具体的な指定が優先される。
スタイルが「カスケード」するという考え方。

カスケード - IT用語辞典

今回使うプロパティ

  • width, height
    • タグの高さ、幅の指定
  • right/left, bottom/top
    • 右/左、下/上からの距離
    • 絶対位置指定の場合は親から、相対の場合は初期位置からの移動

絶対位置と相対位置

  • 絶対位置指定
    • 最も近い親からの相対的位置に配置される
    • 親がいない場合文書全体を基準として配置される
  • 相対位置指定
    • CSSの指示に従い、初期位置から移動

例1 .plant / .plant-holder

    <div id="right-container" class="container">
        <div class="plant-holder">
            <img class="plant" alt="plant" id="plant8" src="./images/plant8.png" />
        </div>
        <div class="plant-holder">
            <img class="plant" alt="plant" id="plant9" src="./images/plant9.png" />
        </div>
        <div class="plant-holder">
            <img class="plant" alt="plant" id="plant10" src="./images/plant10.png" />
        </div>
        <div class="plant-holder">
            <img class="plant" alt="plant" id="plant11" src="./images/plant11.png" />
        </div>
        <div class="plant-holder">
            <img class="plant" alt="plant" id="plant12" src="./images/plant12.png" />
        </div>
        <div class="plant-holder">
            <img class="plant" alt="plant" id="plant13" src="./images/plant13.png" />
        </div>
        <div class="plant-holder">
            <img class="plant" alt="plant" id="plant14" src="./images/plant14.png" />
        </div>
    </div>

.plantに相対、 .plant-holderに絶対位置指定
HTML > .plant_holder > .plant という構成なので、.plant-holderがHTMLに対する絶対位置に固まってしまう。

https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1224564/f2e27677-308d-ceb1-9707-e0189b948a28.png

.plantに絶対、 .plant-holderに相対位置指定
.plant_holderが相対的に配置され、その中に .plantが絶対位置で配置される。

https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1224564/6f9d43d2-1a5a-c505-d384-849c41462685.png

チャレンジ 反射光の実装

divタグにスタイルを指定する形で実装します。

<!-- テラリウム -->
<div id="terrarium">
    <div class="jar-top"></div>
    <div class="jar-walls">
        <!-- 追加箇所 -->
        <div class="jar-glossy-long"></div>
        <div class="jar-glossy-short"></div>
    </div>
    <div class="dirt"></div>
    <div class="jar-bottom"></div>
</div>
.jar-glossy-long {
    /* 幅と高さ */
    width: 3%;
    height: 30%;
    /* 色と透明度 */
    background: rgb(224, 255, 255);
        opacity: 0.7;
    /* ポジションは親に対する絶対位置にしておく */
    position: absolute;
    /* 左から、下からの距離 */
    left: 10%;
    bottom: 20%;
    /* 角を丸める */
    border-radius: 1rem;
}

https://github.com/microsoft/Web-Dev-For-Beginners/raw/main/3-terrarium/2-intro-to-css/images/terrarium-final.png

OK?

副教材

こちらの教材のFlexbox FroggyGrid Garden(無料)が紹介されていました。
超わかりやすいのでオススメです。

Flex Box

flexboxを利用することでブロック要素を柔軟に並び替えることが出来る。

  • 最初に並び替えたいブロック要素の親要素display: flexを指定する。
  • そこから実現したい操作に応じてプロパティを指定していく。

justify-content

アイテムを主軸方向に並べる。

  • flex-start: アイテムはコンテナーの左側に並びます。
  • flex-end: アイテムはコンテナーの右側に並びます。
  • center: アイテムはコンテナーの中央に並びます。
  • space-between: アイテムはその間に等しい間隔を空けて表示されます。
  • space-around: アイテムはその周囲に等しい間隔を空けて表示されます。

align-items

アイテムを直交軸方向に並べる。

  • flex-start: アイテムはコンテナーの上部に並びます。
  • flex-end: アイテムはコンテナーの下部に並びます。
  • center: アイテムはコンテナーの垂直方向中央に並びます。
  • baseline: アイテムはコンテナーのベースラインに表示されます。
  • stretch: アイテムはコンテナーの大きさに合うよう広がります。

flex-direction

コンテナ内でアイテムが配置される方向、すなわち主軸方向を決定する。

  • row: アイテムは文章と同じ方向に配置されます。
  • row-reverse: アイテムは文章と逆の方向に配置されます。
  • column: アイテムは上から下に向かって配置されます。
  • column-reverse: アイテムは下から上に向かって配置されます。

flex-direction注意点

主軸の方向がcolumnのとき、justify-contentは垂直方向の、align-itemsは水平方向の並び方を変えるようになる。

order

個別のアイテムに順番(配列のインデックスと同じイメージ)を適用。
デフォルトで0を取り、正の値/負の値を設定することが出来る。

.yellow {
    order: 1 /* 他が0なら.yellowの要素が最後へ移動する */
}

align-self

align-items と同じ値を受け付け、指定のアイテムの状態だけ変更する。

.yellow {
    align-self: end
}

flex-wrap

  • nowrap: 全てのアイテムは、ひとつの行にフィットします。
  • wrap: アイテムは他の行へ折り返します。
  • wrap-reverse: アイテムは逆順になって他の行へ折り返します。

flex-flow

  • flex-direction flex-wrap を統合したプロパティ。
  • flex-flow: column wrap;のように指定

align-content

  • align-contentは行間の余白を決めるもので、align-itemsはコンテナーに含まれるアイテム全体としての配置を決めるもの。1行だけの場合 align-content は何の意味も持たない。
  • flex-start: 行はコンテナーの上側に詰められます。
  • flex-end: 行はコンテナーの下側に詰められます。
  • center: 行はコンテナーの中央に詰められます。
  • space-between: 行はその間に等しい間隔を空けて表示されます。
  • space-around: 行はその周囲に等しい間隔を空けて表示されます。
  • stretch: 行はコンテナーに合うよう引き延ばされます。

Grid Layout

gridを使うことで格子状のレイアウトを簡単に作ることが出来る。

#garden {
  display: grid;
  /* 行列を5分割する */
  grid-template-columns: 20% 20% 20% 20% 20%;
  grid-template-rows: 20% 20% 20% 20% 20%;
}
  • flexと同じく、親要素に display: grid を指定してからプロパティを適用させていく。

grid-column-start/end

  • Pythonなどで使える配列のスライスのようなイメージ
    • startはN番目の縦線からスタート
    • endはN番目の縦線で終了
    • 言葉だけだとわかりにくいと思うので、ぜひ実際にGrid-Gardenをプレイしてみてください。
  • grid-column-start: 1; grid-column-end: 5; のような形で書く。
    • start: 5 end: 2のような書き方も可能
  • 負の数を指定することも出来る
    • start に負の数を指定した時の挙動に注意

span

  • grid-column: 2 / span 3 のように書く
  • その名の通り、幅を指定できる(正の数のみ)
  • startspanを使えば終了位置までの幅を指定できる

grid-column

  • grid-column: 2 / 4; のように/区切りで値を書くことで開始・終了位置を一度に指定できる。
  • span キーワードも使える。

grid-row

  • 列方向に働く grid-column

grid-area

  • grid-column grid-row を一度に指定できる
  • grid-area: 1/2 / 4/6 のように書く
  • grid-row-start grid-column-start grid-row-end grid-column-endの順で / 区切り

order

  • デフォルトだと order は0で、要素が登場する順番に並ぶ。
  • order: 1 のように指定することで正の値/負の値を自由に設定できる。

複数のグリッドアイテム

  • 複数のグリッドアイテムを重ねることもできる。
#water-1 {
  grid-area: 1 / 4 / 6 / 5;
}

#water-2 {
grid-area: 2/3 / 5/6
}

grid-template-columns

  • grid-template: 50% 20% 30% のように書くことで、格子の幅・高さを指定できる
  • % px em などを受け取れる
  • fr を使える
    • 分数(fractional)の省略
    • 1fr 5fr と指定したとする
      • まず残りのスペースの1/6が計算される。それから、それぞれに1/6、5/6のスペースが与えられる。
    • % などによる指定と共存している場合、%などで指定されたスペースの残りが対象。
      • grid-template-columns: 50px 1fr 1fr 1fr 50px と書けば、左右 50px が割り当てられた後に3分割される。

grid-template

  • row columnを同時に指定できる短縮プロパティ
  • grid-template:1fr 50px / 20% 80% のように書いたとする
    • 列は下側の50px + 上側の残り全て
    • 行は2:8に分かれている

repeat

  • repeat(8, 12.5%) のように書くことで 12.5%を8回分指定できる

DOM操作とクロージャ

DOMとは

Document Object Modelのこと。

マークアップがなされたリソース(Document)をリソース要素(Object)の木構造(Model)で表現し、操作可能にする。 (Wikipedia)

XML文書やHTML文書を構成する要素をコンピュータプログラムで参照したり操作したりするための取り決め(API)。 (IT用語辞典)

特徴

  • ツリー構造(階層構造)を持つ

https://github.com/microsoft/Web-Dev-For-Beginners/raw/main/3-terrarium/3-intro-to-DOM-and-closures/images/dom-tree.png

DOM とそれを参照する HTML マークアップの表現。Olfa Nasraoui より

  • HTML文書をノードを最小単位として表現する
  • ノード間の関係(親子・兄弟関係)が存在し、DOM操作では特定のノードからその親、子などを参照することが出来る
  • DOMにアクセスし、編集・変更・再配置・その他管理をすることでWebページを編集することが出来る。

参考

JavaScriptから操作

dragElement(document.getElementById('plant1'));

このように書くことでDOMで操作したい要素への参照を得ることが出来る。

クロージャとは

MDNによると、

クロージャは、組み合わされた(囲まれた)関数と、その周囲の状態(レキシカル環境)への参照の組み合わせです。言い換えれば、クロージャは内側の関数から外側の関数スコープへのアクセスを提供します。JavaScript では、関数が作成されるたびにクロージャが作成されます。

よくわからないですね・・・

コードを見てみます。

function makeFunc() {
  let name = 'Mozilla';
  function displayName() {
    alert(name);
  }
  return displayName;
}

let myFunc = makeFunc();
myFunc();
  • myFuncmakeFunc の実行結果である displayName 関数への参照。
  • displayName はレキシカル環境への参照を維持するため、 name 変数にアクセスできる。

レキシカル環境って?

静的スコープ - Wikipedia

  • レキシカル=字面上の
  • レキシカルスコープ=静的スコープで、ソースコードの段階でスコープが確定するようなスコープのこと。

つまり?

  • 外側の関数のスコープで変数を定義し、
  • 外側の関数の中に関数を作り、
  • その関数内の関数から外側の関数のスコープで定義した変数を参照できる

Wikipediaによると、

クロージャ (クロージャー、Closure) は、プログラミング言語において引数以外の変数を実行時の環境ではなく、自身が定義された環境(静的スコープ)において解決する関数のことである。

つまり、変数の参照先が実行時の環境(関数の外側)ではなく、自身が定義された環境(静的スコープ・関数の内側)である。
という感じでしょうか。

クロージャによって、こんな事ができます。

function outer() {

    let x = 10;

    function inner() {
        console.log(x)
        x = x + 1
    }

    return inner;
}
let f = outer()

f(); // 10
f(); // 11
f(); // 12

参考

ドラッグ&ドロップで植物を自由に動かせるようにする

JavaScriptによるDOM操作を実装していきます。

  1. まずDOMで操作したい要素への参照を用意する

    dragElement(document.getElementById('plant1'));
    dragElement(document.getElementById('plant2'));
    dragElement(document.getElementById('plant3'));
    // 以下省略
    
  2. dragElement関数を作成

    • 関数に渡されたオブジェクトの位置を初期化
    • pointerdown イベントを登録
      • pointerdown はボタンが押されたとき、あるいはドラッグ可能な要素がタッチされたときに発生。

    実装するクロージャの全体像

    // dragElement : 最も外側の関数
    function dragElement(terrariumElement) {
            let pos1,pos2,pos3,pos4 = 0;
        terrariumElement.onpointerdown = pointerDrag
    
        function pointerDrag() {
                // マウス押下された時に呼ばれる
        }
        function elementDrag() {
                // ドラッグされた時
        }
        function stopElementDrag() {
                // ドロップされた時
        }
    }
    
  3. マウスが押下された時に以下を実行

    • デフォルトのイベント(ドラッグが解除されたら元の位置に戻る)を無効化
    • マウスカーソルの初期位置を取得し、pos3 pos4に入れる
      • evnet.clientX/Y で取得
    • マウス移動時/停止時のイベントを割り当て
    function dragElement(terrariumElement) {
    
        let pos1,pos2,pos3,pos4 = 0;
        terrariumElement.onpointerdown = pointerDrag
    
        function pointerDrag(e) {
            // デフォルトのイベントを防ぐ
            e.preventDefault
            // マウスカーソルの初期位置を取得
            pos3 = e.clientX
            pos4 = e.clientY
    
            document.onpointermove = elementDrag;
            document.onpointerup = stopElementDrag;
        }
    
        function elementDrag() {
    
        }
    
        function stopElementDrag() {
    
        }
    }
    
  4. マウス移動時に以下を実行

    • 外側で定義したpos1~4を更新
    • terrariumElement のスタイル(座標情報)を更新
    function elementDrag() {
        // pos1 = xの[過去の位置-現在の位置] (移動距離)
        pos1 = pos3 - e.clientX;
        pos2 = pos4 - e.clientY;
        //pos3, 4を現在位置にリセット
        pos3 = e.clientX;
        pos4 = e.clientY;
        console.log(pos1, pos2, pos3, pos4);
        // Elementの新しい位置を設定
        terrariumElement.style.top = terrariumElement.offsetTop - pos2 + 'px';
        terrariumElement.style.left = terrariumElement.offsetLeft - pos1 + 'px';
        }
    
  5. マウス停止時に onpointermove/up のイベントをnullにする

    • こうしないとpointermove時に実行される関数が残ってしまう
    function stopElementDrag() {
            document.onpointermove = null;
            document.onpointerup = null;
        }
    

完成!

https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1224564/3683e3e0-5967-a69d-0bad-90550a7e9481.gif

副教材

学んだこと

  • HTMLの基礎について
  • CSSの基礎について
  • flexboxについて
    • display: flexを使えばブロック要素を柔軟に並べることが出来る。
  • Grid Layoutについて
    • display: gridを使えば格子状のレイアウトを簡単に作ることが出来る。
  • 簡単なDOM操作、クロージャについて
    • JavaScriptからWebページを操作する時はDOM操作を多用する。
    • 今回の実装ではアプリ全体を1つの大きなクロージャとして構築することで、複数のドラッグ可能なオブジェクトのそれぞれのスコープを簡単に維持するができた。
1
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
4