はじめに

この文書はWeb開発の入門ガイドです。 Web開発を進めていくための助けになれば幸いです。

目次

― この文書は © 2023 MDN Web Docsプロジェクト協力者 クリエイティブ・コモンズ CC BY SA 2.5 ライセンスのもとに利用を許諾されています。 元の文書: https://developer.mozilla.org/ja/docs/Learn/Getting_started_with_the_web/What_will_your_website_look_like

Web開発入門

Web開発を始める前に考えておかなければいけないことがあります。Webサイトは様々なことができます。しかし複雑なものを開発するとしても、はじめはできるだけ単純なものから少しずつ理解を深めていくべきでしょう。

まずは、見出し、画像、段落のある単純なWebページを作ることから始めましょう。

  1. 何についてのWebページ? 犬、ニューヨーク、それともパックマン?
  2. どんな情報? タイトルといくつかの段落、それからページに表示させたい画像を考えます。
  3. どんな見た目? 簡単で大まかな言葉で言うと?背景色は?適切なフォントはフォーマル?漫画?太字で派手?繊細?

デザインをスケッチする

次に、ペンと紙を取ってサイトの見た目をどういう風にしたいのか大まかに描き出します。はじめてのシンプルなWebページでは、描き出すものもあまりないかもしれませんが、作る上での習慣にしましょう。(ヴァン・ゴッホのようになる必要はありません)

紙に描いたWebサイトのラフ画とスケッチ

Note 現実の複雑なWebサイトの場合でも、デザインチームは普通、ラフスケッチを描くことから始めます。その後、グラフィックエディターや Web の技術を使って、デジタルのモックアップを作るのです。

多くの場合、Webの開発チームには、グラフィックデザイナーとユーザーエクスペリエンス (UX) デザイナーがいます。グラフィックデザイナーは、Webサイトの見た目を作り上げます。 UX デザイナーは、もう少し抽象的な役割を持っていて、サイトを訪れるユーザーがWebサイトでどういう経験をし、どのように操作するかということを考えます。

この時点で、Webページについて、どう表現したいかをまとめ始めていきましょう。

テキストエディター

Visual Studio Codeなどのテキストエディターを使用して忘れないようにメモしておきましょう。

フォルダー

フォルダーは簡単に見つけることができる場所、たとえばデスクトップ上、ホームフォルダーの中、Cドライブのルートなどに置きましょう。

  1. Webサイトプロジェクトを保存する場所を選択してください。ここでは web-projects (またはそのようなもの)という新しいフォルダーを作成します。これはWebサイトのプロジェクト全体を保存するところです。
  2. フォルダーの中に、最初のWebサイトを格納する別のフォルダーを作成します。それを test-site と呼びましょう(もっとユニークなものでもOK)。

コンテンツ

  • タイトル: Mozilla is cool (例)
  • 内容: Mozilla is cool (例)

テーマカラー

色を選ぶときは、「カラー選択ツール」と検索し、好みの色を見つけましょう。色をクリックすると、 #fcba03 のような "#" + 6 桁の奇妙なコードが出てきます。これはヘキサコード(16 進数コード、0, 1, 2, ..., 9, a, b, ..., f までの16種類の数字を使うコード)と呼ばれ、選んだ色を表します。このコードはあとで使うのでコピーしておきましょう。

画像

画像を探すには、Google 画像検索にアクセスし、ぴったりなものを探しましょう。

  1. 欲しい画像が見つかったら、クリックして拡大表示にします。
  2. 画像を右クリック(Mac では Ctrl +クリック)し、[名前を付けて画像を保存...] を選択して、画像を安全に保存する場所を選択します。または、後で使用するためにブラウザーのアドレスバーから画像のWebアドレスをコピーします。

Google 画像検索での検索語句の検索結果

なお、Web上のほとんどの画像には、 Google 画像検索にあるものも含め、著作権があります。あなたが著作権を侵害してしまうことを防ぐために、 Google のライセンスフィルターを使うと良いでしょう。 [ツール] ボタンをクリックすると、 [ライセンス] オプションが下に表示されます。「クリエイティブ・コモンズ ライセンス」などの選択肢を選択してください。

Google 画像検索でクリエイティブ・コモンズ ライセンスの画像を取得するための検索結果のフィルタリング

Note
クリエイティブ・コモンズ・ライセンス (CCライセンス) とは

CCライセンスとはインターネット時代のための新しい著作権ルールで、作品を公開する作者が「この条件を守れば私の作品を自由に使って構いません。」という意思表示をするためのツールです。

CCライセンスを利用することで、作者は著作権を保持したまま作品を自由に流通させることができ、受け手はライセンス条件の範囲内で再配布やリミックスなどをすることができます。

クリエイティブ・コモンズ・ライセンスとは | クリエイティブ・コモンズ・ジャパン より

― この文書は © 2023 MDN Web Docsプロジェクト協力者 クリエイティブ・コモンズ CC BY SA 2.5 ライセンスのもとに利用を許諾されています。 元の文書: https://developer.mozilla.org/ja/docs/Learn/Getting_started_with_the_web/Dealing_with_files

ファイルの扱い

Webサイトは、テキストコンテンツ、コード、スタイルシート、メディアコンテンツなど、多くのファイルで構成されています。ここでは注意すべきいくつかの点を説明します。

コンピューター上でWebサイトがあるべき場所

コンピューター上のWebサイトの開発作業している時もWebサイトのファイルとフォルダーの構造は実際のWebサイトと同じようにしましょう。

フォルダーは簡単に見つけることができる場所、たとえばデスクトップ上、ホームフォルダーの中、Cドライブのルートなどに置きましょう。

  1. Webサイトプロジェクトを保存する場所を選択してください。ここでは web-projects (またはそのようなもの)という新しいフォルダーを作成します。これはWebサイトのプロジェクト全体を保存するところです。
  2. フォルダーの中に、最初のWebサイトを格納する別のフォルダーを作成します。それを test-site と呼びましょう(もっとユニークなものでもOK)。

ファイル名・フォルダー名には日本語・大文字・空白を使わない

この文書ではフォルダーやファイルに空白のない全て半角小文字の名前を付けるよう求めています。理由は次の通りです。

  1. 多くのコンピューター、特にWebサーバーでは、大文字と小文字が区別されます。例えば、Webサイトの test-site/MyImage.jpg に画像を置いて、別のファイルから画像を test-site/myimage.jpg として呼び出そうとすると、動作しないかもしれません。
  2. ブラウザー間、Webサーバー間、プログラミング言語間で、空白の扱いが一貫していません。例えば、ファイル名に空白を使用すると、システムによってはそのファイル名を 2 つのファイル名として扱うことがあります。サーバーによっては、ファイル名の空白を "%20" (URL の空白の文字コード)に置き換えるので、リンクが壊れてしまう結果になります。my_file.html のように単語をアンダースコアで区切るよりは、my-file.html のようにハイフンで区切った方がよいでしょう。

Webサイトはどのような構成にするべきか

Webサイトプロジェクトで最も一般的なフォルダー構成は、(1) 目次の HTML ファイル、(2) 画像ファイル、(3) スタイルシート (見た目に関するコード)、(4) スクリプトファイル (JavaScriptのコード) を入れるフォルダーです。作成してみましょう。

  1. index.html: このファイルには、一般的にあなたのホームページの内容、つまりあなたが最初にあなたのサイトに行ったときに見るテキストと画像が含まれています。テキストエディターを使用して、 index.html という名前の新しいファイルを作成し、 test-site フォルダー内に保存します。
  2. images フォルダー: このフォルダーにはサイトで使用するすべての画像を入れます。test-site フォルダーの中に images という名前のフォルダーを作成します。
  3. styles フォルダー: このフォルダーには、コンテンツのスタイルを設定するための CSS コード(例えばテキストと背景色の設定など)を入れます。 styles というフォルダーを test-site のフォルダーの中に作成します。
  4. scripts フォルダー: このフォルダーには、サイトに対話機能を追加するために使用されるすべての JavaScript コード(クリックされたときにデータを読み込むボタンなど)が含まれます。 scripts というフォルダーを test-site のフォルダーの中に作成します。

Note Windows では、既定で有効になっている既知のファイルの種類の拡張子を表示しないというオプションがあるため、ファイル名の表示に問題が発生することがあります。一般に、 Windows エクスプローラーで [フォルダーオプション...] オプションを選択し、[登録されている拡張子は表示しない] チェックボックスをオフにし、 [OK] をクリックすることで、これをオフにすることができます。お使いの Windows のバージョンに関する詳細な情報については、Webで検索してください。

ファイルパス

ファイルをお互いに呼び出すためには、ファイルパスを提供する必要があります。

画像ファイルは既存の画像を自由に選択して、以下の手順で使用することができます。

  1. 以前に選択した画像を images フォルダーにコピーします。

  2. index.html ファイルを開き、次のコードをファイルに挿入します。それが今のところ何を意味するのか気にしないでください。シリーズの後半で構造を詳しく見ていきます。

    <!doctype html>
    <html lang="ja">
      <head>
        <meta charset="utf-8" />
        <meta name="viewport" content="width=device-width" />
        <title>テストページ</title>
      </head>
      <body>
        <img src="" alt="テスト画像" />
      </body>
    </html>
    
  3. <img src="" alt="テスト画像"> という行は、ページに画像を挿入する HTML コードです。画像がどこにあるのかを HTML に伝える必要があります。画像は images ディレクトリー内にあり、index.html と同じディレクトリーにあります。ファイル構造の中で index.html からその画像に移動するのに必要なファイルパスは images/your-image-filename です。例えば、私たちの画像は firefox-icon.png と呼ばれており、ファイルパスは images/firefox-icon.png になります。

  4. src="" コードの二重引用符の間の HTML コードにファイルパスを挿入してください。

  5. alt 属性の内容を入れようとしている画像の説明に変更してください。今回は、 alt="Firefoxのロゴ" とします。

  6. HTML ファイルを保存し、Webブラウザーに読み込みます(ファイルをダブルクリックします)。新しいWebページに画像が表示されます。

ファイルパスの一般的なルールは次の通りです。

  • 呼び出し元の HTML ファイルと同じディレクトリーにある対象ファイルにリンクするには、ファイル名を使用します。例えば my-image.jpg
  • サブディレクトリー内のファイルを参照するには、パスの前にディレクトリー名とスラッシュを入力します。例えば subdirectory/my-image.jpg
  • 呼び出し元の HTML ファイルの上階層のディレクトリー内にある対象ファイルにリンクするには、2 つのドットを記述します。例えば、index.htmltest-site のサブフォルダー内にあり、my-image.jpgtest-site 内にある場合、../my-image.jpg を使用して index.html から my-image.jpg を参照できます。
  • 例えば ../subdirectory/another-subdirectory/my-image.jpg など、好きなだけ組み合わせることができます。

Note Windows のファイルシステムでは、スラッシュ (/) ではなくバックスラッシュまたは¥記号を使用します(例 : C:\Windows)。これは HTML では使用できません。Windows でWebサイトを開発している場合でも、コード内ではスラッシュを使用する必要があります。

他にするべきこと

今のところは以上です。フォルダー構造は次のようになります。

macOS X の finder におけるファイル構造。images フォルダーに画像が入っており、scripts と styles フォルダーは空で、あと index.html がある

― この文書は © 2023 MDN Web Docsプロジェクト協力者 クリエイティブ・コモンズ CC BY SA 2.5 ライセンスのもとに利用を許諾されています。 元の文書: https://developer.mozilla.org/ja/docs/Learn/Getting_started_with_the_web/HTML_basics

HTMLの基本

HTML (HyperText Markup Languageハイパーテキスト・マークアップ・ランゲージ)は、Webページの構造を記述するための言語です。例えば、コンテンツは段落、箇条書きのリスト、画像の使用、データテーブルなどの組み合わせで構成されています。

HTML は一連の 要素 で構成されており、これらの要素がコンテンツのさまざまな部分を囲み、一定の表示や動作をさせることができます。タグで囲むと、単語や画像をどこかにハイパーリンクさせたり、単語を斜体にしたり、フォントを大きくしたり小さくしたりすることができます。 例えば、次のようなコンテンツがあるとします。

My cat is very grumpy

行を独立させたい場合は、段落タグで囲んで段落であることを指定することができます。

<p>My cat is very grumpy</p>

HTML 要素の中身

この段落要素についてもう少し詳しく見ていきましょう。

開始タグ、 'my cat is very grumpy' と読めるコンテンツ、終了タグがある段落要素

要素は主に以下のようなもので構成されています。

  1. 開始タグ (opening tag): これは、要素の名前(この場合は p)を山括弧で囲んだものです。どこから要素が始まっているのか、どこから効果が始まるのかを表します。 — 今回の場合どこから段落が始まるかを表しています。
  2. 終了タグ (closing tag): これは、要素名の前にスラッシュが入っていることを除いて開始タグと同じです。どこで要素が終わるのかを表しています。 — この場合は、段落が終わる場所を表します。終了タグの書き忘れは、初心者のよくある間違いで、おかしな結果になることがあります。
  3. コンテンツ (content): 要素の内容です。今回の場合はただのテキストです。
  4. 要素 (element): 開始タグ、終了タグ、コンテンツで要素を構成します。

要素には属性 (attribute) を設定することができます。このような感じです。

class 属性 class=editor-note が強調された段落の開始タグ

属性には、実際のコンテンツには表示させたくない、要素に関する追加情報が含まれています。ここでは、 class が属性の名前で、 editor-note が属性のです。 class 属性では、要素に一意ではない識別子を与えることができ、それを使って要素(および同じ class 値を持つ他の要素)にスタイル情報などのターゲットを設定することができます。 一部の属性、たとえば required には値がありません。

値を設定する属性は常に次のような形式になります。

  1. 要素名(すでにいくつか属性がある場合はひとつ前の属性)との間の空白
  2. 属性名とそれに続く等号
  3. 引用符で囲まれた属性の値

Note ASCII のホワイトスペース(または " ' ` = < > のいずれかの文字)を含まない単純な属性値は引用符を省略することができますが、コードを一貫性のあるものにし、理解を容易にするため、すべての属性値を引用符で囲むことをお勧めします。

要素の入れ子

要素の中に他の要素を入れることもできます。これをネスト(または入れ子)と言います。もしあなたの猫が「とっても」機嫌が悪いことを表したいとしたら、「とっても」という単語を <strong> 要素に入れて、単語の強調を表すことができます。

<p>My cat is <strong>very</strong> grumpy.</p>

しかしながら要素は正しく入れ子にしなければなりません。上記の例では、まず始めに <p> 要素が開始され、その次に <strong> 要素が開始されています。その場合は、必ず <strong> 要素、 <p> 要素の順で終了しなければなりません。次の例は間違いです。

<p>My cat is <strong>very grumpy.</p></strong>

要素は確実に他の要素の中もしくは外で開始し、終了する必要があります。上記の例のように要素が重複してしまうと、Webブラウザーは言おうとしていることを推測してもっとも良いと思われる解釈をするため、予期せぬ結果になることがあります。そうならないよう気を付けましょう!

空要素

コンテンツを持たない要素もあります。そのような要素を 空要素 (void element) と呼びます。すでに HTML ページにある <img> 要素を例に見ていきましょう。

<img src="images/firefox-icon.png" alt="テスト画像" />

この要素は 2 つの属性を持っていますが、終了タグ </img> がありませんし、内部にコンテンツもありません。これは画像要素は、その機能を果たすためにコンテンツを囲むものではないからです。画像要素の目的は、画像を HTML ページの表示させたいところに埋め込むことです。

HTML 文書の構造

ここまでは HTML 要素について見てきましたが、しかし、要素単体ではあまり役には立ちません。ここからはどのようにしてそれぞれの要素を組み合わせ、 HTML ページ全体を作っていくのかを勉強していきましょう。ファイルの扱いで出てきた index.html に書いてあるコードをもう一度見てみましょう。

<!doctype html>
<html lang="ja">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width" />
    <title>テストページ</title>
  </head>
  <body>
    <img src="images/firefox-icon.png" alt="テスト画像" />
  </body>
</html>

この中にあるものは以下の通りです。

  • <!DOCTYPE html>文書型宣言です。これは必須の前置きです。昔々、 HTML がまだ出来たばかりの頃(1991 ~ 2 年)、文書型宣言は HTML ページが正しい HTML と見なされるために従わなければならない、一連のルールへのリンクとして機能することを意味していました。つまり、自動エラーチェックなどの有益なものを表すことができました。しかし、最近ではあまり機能しておらず、文書が正しく動作するために必要なだけです。今はこれだけ知っていれば大丈夫です。
  • <html></html> — <html> 要素です。この要素は、このページのすべてのコンテンツを囲み、ルート要素と呼ばれることもあります。ここでは文書の主要な言語を設定する lang 属性も指定します。
  • <head></head> — <head> 要素です。この要素は、ページの閲覧者に向けて表示するためのコンテンツではない、 HTML ページに含めたいものをすべて収めるための入れ物です。検索エンジン向けの キーワード やページのディスクリプション(説明書き)、ページの見た目を変更するための CSS、文字コードの宣言などを含みます。
  • <meta charset="utf-8"> — この要素は、大部分の書き言葉の文字のほとんどを含む UTF-8 を文書で使用するように設定しています。基本的には、文書はどんなテキストコンテンツでも扱えるようになります。これを設定しない理由はありませんし、後でいくつかの問題を回避するのに役立ちます。
  • <title></title> — <title> 要素です。ページのタイトルを指定しています。このタイトルはページが読み込まれた時にブラウザーのタブに表示されます。また、ブックマークやお気に入りに登録した時の説明にも使われます。
  • <meta name="viewport" content="width=device-width"> — このビューポート属性は、このページがある幅のビューポートで描画されることを保証し、モバイルブラウザーがビューポートより広い幅でページを描画した上で縮小して表示するのを防止します。
  • <body></body> — <body> 要素です。これには、テキスト、画像、ビデオ、ゲーム、再生可能な音声トラックなど、ページを訪れたWebの利用者に表示したいすべてのコンテンツが含まれます。

画像

もう一度 <img> 要素について見ていくことにしましょう。

<img src="images/firefox-icon.png" alt="テスト画像" />

前に説明したように、ページのこれが現れたところに画像を埋め込みます。画像ファイルのパスを値に持つ src (source) 属性を指定することによってその画像を表示できます。

また、 alt (alternative; 代替) 属性も指定しています。 alt 属性は、以下のような理由で画像を見られない人に向けて説明するテキストを指定するものです。

  1. 目が不自由な人。著しく目の不自由な人はよくスクリーンリーダーと呼ばれるツールを使っていて、それが画像の alt 属性の内容を読み上げます。
  2. 何らかの理由で画像の表示に失敗した場合。例えば、 src 属性の中のパスをわざと正しくないものに変更してみてください。ページを保存したり再読み込みしたりすると、画像の場所に下記のようなものが表示されるでしょう。

テスト画像という言葉

alt テキストのキーワードは「説明文」です。 alt テキストは、その画像が何を伝えているのかを読者が十分に理解できるような情報を提供する必要があります。この例では、現在のテキストである「テスト画像」は全く意味がありません。 Firefox のロゴであれば、「Firefox のロゴ: 地球の周りを燃えるような狐が囲んでいる。」の方がずっと良いでしょう。

画像に良い代替文字列を付けてみましょう。

Note アクセシビリティについて詳しくは MDN のアクセシビリティのページを参照してください。

テキストのマークアップ

この節では、文字列をマークアップするために使用する基本的な HTML 要素をいくつか見ていきます。

見出し

見出し要素により、コンテンツの特定の部分を見出し、または小見出しとして指定することができます。本にメインタイトル、章立て、サブタイトルがあるように、 HTML 文書にも見出しがあります。 HTML には <Heading_Elements", "<h1> - <h6>> の 6 段階の見出しがありますが、よく使うのはせいぜい 3 から 4 まででしょう。

<!-- 4 段階の見出し -->
<h1>メインタイトル</h1>
<h2>最上位の見出し</h2>
<h3>小見出し</h3>
<h4>孫見出し</h4>

Note HTML の中で <!----> の間にあるものは、すべて HTML コメントです。ブラウザーは、コードを表示する際にコメントを無視します。つまり、コメントはページ上では表示されず、コードの中に表示されるだけです。 HTMLコメントは、コードやロジックに関する有用なメモを書き込むためのものです。

それでは、あなたの HTML の <img> 要素の上に適切なタイトルを付けてみましょう。

Note 見出しレベル 1 には、暗黙のスタイルがあることがわかりますね。テキストを大きくしたり、太くしたりするために見出し要素を使用しないでください。見出し要素はアクセシビリティSEO などの理由で使用されているからです。段階を飛ばすことなく、意味のある見出しの並びをページ上に作るようにしてください。

段落

先に説明したように、 <p> 要素は段落を示しています。通常の文章を書くときにはこの要素を頻繁に使うことになるでしょう。

<p>This is a single paragraph</p>

サンプルテキストを (「Webサイトをどんな外見にするか」から持ってきてください) 1 つまたは複数の段落に入れ、 <img> 要素のすぐ下に配置してください。

リスト

Webのコンテンツの多くはリストであり、 HTML にはリストのための特別な要素があります。リストのマークアップは、常に 2 つ以上の要素で構成されています。最も一般的なリストの種類は、順序付きリストと順序なしリストです。

  1. 順序なしリストは、お買い物リストのようにアイテムの順番が特に関係ない時に使います。順序なしリストは <ul> 要素で囲みます。
  2. 順序付きリストは料理のレシピのようにアイテムの順番が関係ある時に使います。順序付きリストは <ol> 要素で囲みます。

リストの中に入るそれぞれのアイテムは <li> (list item) 要素の中に書きます。

例えば、次の段落の一部をリストにしたい場合、

<p>
  At Mozilla, we're a global community of technologists, thinkers, and builders
  working together…
</p>

以下のようにマークアップします。

<p>At Mozilla, we're a global community of</p>

<ul>
  <li>technologists</li>
  <li>thinkers</li>
  <li>builders</li>
</ul>

<p>working together…</p>

ページに番号付きリストと番号なしリストを追加してみましょう。

リンク

リンクはとても重要です。これがWebをWebたらしめているものです。リンクを追加するには、シンプルな要素 <a> を使う必要があります。 a は "anchor" を省略したものです。段落中の文字をリンクにするには次の手順で行います。

  1. リンクにしたい文字を選びます。今回は "Mozilla Manifesto" を選びました。

  2. 選んだ文字を <a> 要素で囲みます。

    <a>Mozilla Manifesto</a>
    
  3. このように <a> 要素に href 属性を追加します。

    <a href="">Mozilla Manifesto</a>
    

    このリンクのリンク先になるWebアドレスを、この属性の値に書き込みます。

    <a href="https://www.mozilla.org/en-US/about/manifesto/">
      Mozilla Manifesto
    </a>
    

アドレスの先頭にある https://http:// の部分(プロトコルと言います)を書き忘れると、予期せぬ結果となってしまうかもしれません。リンクを作ったら、ちゃんとそれが遷移したいところに行ってくれるかを確かめましょう。

Note href は属性名として変に思うかもしれません。覚えにくかったら、 hrefhypertext reference を表しているということを覚えておきましょう。

もしまだやってないのなら、ページにリンクを追加してみましょう。

まとめ

説明に沿ってやってきたら以下のようなページが出来上がっているかと思います (もちろん画像やテキストの内容はみなさんの自由です)。

Webページのスクリーンショットで、 Firefox のロゴ、「Mozilla is cool」という見出し、そして 2 段落のテキストが表示されています。

もし途中で行き詰まってしまったら、「サンプルコード」と見比べてみましょう。

― この文書は © 2023 MDN Web Docsプロジェクト協力者 クリエイティブ・コモンズ CC BY SA 2.5 ライセンスのもとに利用を許諾されています。 元の文書: https://developer.mozilla.org/ja/docs/Learn/Getting_started_with_the_web/CSS_basics

CSSの基本

CSS (Cascading Style Sheets) は、Webページのスタイルを設定するコードです。ここでは、始めるのに必要なものを紹介します。ここでは、テキストを赤くするにはどうすればいいのか?コンテンツを(Webページの)レイアウトの中で特定の場所に表示するにはどうすればいいのか?背景画像と色を使って Webページをどのように飾るのか?というような疑問に答えていきます。

例えば、この CSS は段落のテキストを選択し、色を赤に設定しています。

p {
  color: red;
}

それでは試してみましょう。テキストエディターを使用して、(上記の) 3 行の CSS 新しいファイルに貼り付けてください。そのファイルを style.css として styles という名前のディレクトリーに保存してください。

コードを働かせるには、この(上記の) CSS を HTML 文書に適用する必要があります。そうしないと、このスタイルはブラウザーの HTML 文書の表示に影響しません。

  1. index.html ファイルを開き、先頭(<head> タグと </head> タグの間)に以下の行を貼り付けてください。

    <link href="styles/style.css" rel="stylesheet" />
    
  2. index.html を保存し、ブラウザーで読み込んでください。次のように表示されるはずです。

Firefoxのロゴといくつかの段落です。段落のテキストは、 CSS によって赤くスタイル付けされています。

段落のテキストが赤くなっていれば、おめでとう! CSS が動作しています。

CSS ルールセットの構造

赤い段落テキストの CSS コードを分解して、その仕組みを理解してみましょう。

CSS の p の宣言で、color を red にする

全体の構造はルールセットと呼びます (ルールセットという語はよく、単にルールとも呼ばれます)。それぞれの部分の名前にも注意してください。

  • セレクター (Selector)
    • : これはルールセットの先頭にある HTML 要素名です。これはスタイルを設定する要素 (この例の場合は <p> 要素) を定義します。別の要素をスタイル付けするには、セレクターを変更してください。
  • 宣言 (Declaration)
    • : color: red; のような単一のルールです。これは要素のプロパティのうち、スタイル付けしたいものを指定します。
  • プロパティ (Property)
    • : これらは、 HTML 要素をスタイル付けするための方法です。 (この例では、 color は <p> 要素のプロパティです。) CSS では、ルールの中で影響を与えたいプロパティを選択します。
  • プロパティ値 (Property value)
    • : プロパティの右側には—コロンの後に—プロパティ値があります。与えられたプロパティの多くの外観から 1 つを選択します。 (例えば、 color の値は red 以外にもたくさんあります。)

構文の他の重要な部分に注意してください。

  • セレクターを除き、それぞれのルールセットは中括弧 ({}) で囲む必要があります。
  • それぞれの宣言内では、コロン (:) を使用してプロパティと値を分離する必要があります。
  • それぞれのルールセット内でセミコロン (;) を使用して、それぞれの宣言と次のルールを区切る必要があります。

一つのルールセットで複数のプロパティ値を変更するには、次のようにセミコロンで区切って書いてください。

p {
  color: red;
  width: 500px;
  border: 1px solid black;
}

複数の要素の選択

複数の要素を選択して、そのすべてに一つのルールセットを適用することもできます。複数のセレクターはカンマで区切ります。たとえば、以下のようになります。

p,
li,
h1 {
  color: red;
}

さまざまな種類のセレクター

セレクターにはさまざまな種類があります。上記の例では、要素セレクターを使用しており、特定の種類の要素をすべて選択しています。しかし、もっと特定の要素を選択することもできます。ここでは、より一般的なセレクターの種類を紹介します。

セレクター名 選択するもの
要素セレクター(タグまたは型セレクターと呼ばれることもあります) 指定された型のすべての HTML 要素。 p
<p> を選択
ID セレクター 指定された ID を持つページ上の要素です。指定された HTML ページでは、各 id 値は一意でなければなりません。 #my-id
<p id="my-id"> または <a id="my-id"> を選択
クラスセレクター 指定されたクラスを持つページ上の要素です。同じクラスの複数のインスタンスが 1 つのページに現れることがあります。 .my-class
<p class="my-class"> および <a class="my-class"> を選択
属性セレクター 指定された属性を持つページ上の要素です。 img[src]
<img src="myimage.png"> は選択するが <img> は選択しない
擬似クラスセレクター 指定された要素が指定された状態にあるとき。(例えば、マウスポインターが上に乗っている(ホバー)状態。) a:hover
<a> を、マウスポインターがリンク上にあるときのみ選択。

他にも様々なセレクターがあります。詳しくは、 MDN のセレクターガイドをご覧ください。

フォントとテキスト

CSS の基本をいくつか勉強しましたので、style.css ファイルにいくつかのルールと情報を追加して、この例を見栄え良くしましょう。

HTML 本文内にテキストを配置する要素 (<h1>, <li>, <p>) のフォントの大きさを設定します。また、見出しを中央揃えにします。最後に、 2 つ目のルールセット (下記) を展開して、行の高さや文字の間隔などの設定を行い、本文のコンテンツを読みやすくしましょう。

h1 {
  font-size: 60px; /* px は「ピクセル」 (pixels) の意味。60 ピクセルの高さのフォントになります */
  text-align: center;
}

p,
li {
  font-size: 16px;
  line-height: 2;
  letter-spacing: 1px;
}

px の値はお好みで調整してください。進行中の作品は、このようになるはずです。

Firefoxのロゴといくつかの段落。 sans-serif フォントが設定され、フォントの大きさ、行の高さ、文字の間隔が調整され、メインページの見出しが中央に配置されています。

CSS: ボックスのすべて

CSS を書いていて気づくことがあります。それは、その多くがボックスに関するものだということです。これには、サイズ、色、位置の設定が含まれます。ページ上のほとんどの HTML 要素は、他の箱の上に置かれた箱と考えることができます。

大きな箱や木箱が積み重なっている状態

Photo from https://www.geograph.org.uk/photo/3418115 Copyright © Jim Barton cc-by-sa/2.0

CSS のレイアウトは、主にボックスモデルに基づいています。ページ上のスペースを占める各ボックスには、次のようなプロパティがあります。

  • padding: コンテンツの周囲のスペースです。以下の例では、段落テキストの周りのスペースです。
  • border: padding のすぐ外側にある実線
  • margin: 要素の外側の周りの空間

3 つのボックスがお互いの内側に配置されています。外側から内側に向かって、 margin, border, padding と書かれています。

この節では次のものを使用します。

  • width (要素の幅)
  • background-color: 要素の内容と padding の背後にある色
  • color: 要素のコンテンツ (通常はテキスト) の色
  • text-shadow: 要素内のテキストに影を設定します
  • display: 要素の表示モードを設定します (これについてはまだ心配しないでください)

続けて、さらに CSS を追加していきましょう。 style.css の一番下に、これらの新しいルールを追加し続けます。値を変えてどうなるか実験してみましょう。

ページの色を変更する

html {
  background-color: #00539f;
}

このルールはページ全体の背景色に設定を行います。上記のカラーコードを、Webサイトをどんな外見にするかで選んだ色に変更しましょう。

本文のスタイル付け

body {
  width: 600px;
  margin: 0 auto;
  background-color: #ff9500;
  padding: 0 20px 20px 20px;
  border: 5px solid black;
}

次は <body> 要素です。ここにはいくつかの宣言がありますので、 1 行ずつ見て行きましょう。

  • width: 600px; — これにより body は常に 600 ピクセルの幅になります。
  • margin: 0 auto;marginpadding などのプロパティに 2 つの値を設定すると、最初の値は要素の上下の辺に影響します(この場合は 0 になります)。2 番目の値は左右に影響します(ここで auto は残った水平方向の余白を左右に均等に配分する特別な値です)。 margin の構文で説明しているように、 1 つ、2 つ、3 つ、4 つの値を使用することもできます。
  • background-color: #FF9500; — これは要素の背景色を設定します。このプロジェクトでは body の背景色に明るいオレンジ色を使用して、 <html> 要素の暗い青とは対照的にしました。(気軽に試してみてください。)
  • padding: 0 20px 20px 20px; — これはパディングに 4 つの値を設定します。これは、コンテンツの周りに少しのスペースを確保するためです。今回は body の上にパディングを設定せず、左・下・右に 20 ピクセルを設定します。値は上・右・下・左の順に設定されます。margin と同様、 padding の構文で説明されているように、 1 つ、 2 つ、または 3 つの値を使用することもできます。
  • border: 5px solid black; — これは境界の太さ、スタイル、色の値を設定します。この場合は、 body の全側面に 5 ピクセルの太さの黒ベタの境界線を設定します。

メインページのタイトルの配置とスタイル付け

h1 {
  margin: 0;
  padding: 20px 0;
  color: #00539f;
  text-shadow: 3px 3px 1px black;
}

body の上部にひどい隙間があることに気づいたかもしれません。これは CSS をまったく適用していなくても、ブラウザーが(他のものの中で) <Heading_Elements", "h1> 要素に既定のスタイルを適用するためです。それは悪い考えのように見えるかもしれませんが、スタイルのないページにも一定の読みやすさを求めるためのものです。隙間をなくすために、 margin: 0; を設定して既定のスタイルを上書きします。

次に見出しの上下のパディングを 20 ピクセルに設定します。

続いて、見出しテキストが HTML の背景色と同じ色になるように設定します。

最後に、 text-shadow は要素のテキストコンテンツに影を適用します。 4 つの値は次のとおりです。

  • 最初はピクセル値で、影のテキストからの水平オフセット、どれだけ横に移動するかを設定します。
  • 2 番目はピクセル値で、影のテキストから垂直オフセット、どれだけ下に移動するかを設定します。
  • 3 番目のピクセル値で、影をぼかす半径を設定します。値が大きいほどぼやけた影を生成します。
  • 4 番目の値は、影の基本色を設定します。

いろいろな値を試して、表示方法の変化を確認してみてください。

画像のセンタリング

img {
  display: block;
  margin: 0 auto;
}

次に、画像を中央に配置して見栄えを良くします。本文のときと同じように、 margin: 0 auto のトリックを使うこともできます。しかし、 CSS を機能させるために追加の設定が必要になる違いがあります。

<body> はブロック要素であるため、ページの中でスペースを占めます。ブロック要素は、マージンやその他の余白を開ける値を適用することができます。一方、画像はインライン要素です。インライン要素にマージンやその他の余白を開ける値を適用することはできません。画像にマージンを適用するには、display: block; を使用して画像にブロックレベルの動作を指定する必要があります。

Note 上記の手順は、本体に設定されている幅 (600 ピクセル) よりも小さい画像を使用していることを前提としています。画像が大きい場合、それは本文をあふれ、ページの残りの部分にはみ出します。これを修正するには、1) 画像編集ソフトを使用して画像の幅を縮小するか、2) CSS を使用して、 width プロパティでより小さな値を <img> 要素に設定し、画像の大きさを変更します。

Note display: block; や、ブロックレベル/インラインの区別がまだ理解できなくても心配しないでください。 CSS の勉強を続けていくうちに意味が分かってくるはずです。さまざまな display の値の違いについて詳しくは、 MDN の display のリファレンスページを参照してください。

まとめ

完成すると次のようなページが表示されます。

Firefoxのロゴを中央に配置し、ヘッダーと段落を配置しています。これで、ページ全体の背景が青くなり、中央に配置されたメインコンテンツストリップの背景がオレンジになるなど、きれいなスタイルになりました。

もし途中で行き詰まってしまったら、「サンプルコード」と見比べてみましょう。

― この文書は © 2023 MDN Web Docsプロジェクト協力者 クリエイティブ・コモンズ CC BY SA 2.5 ライセンスのもとに利用を許諾されています。 元の文書: https://developer.mozilla.org/ja/docs/Learn/Getting_started_with_the_web/JavaScript_basics

JavaScriptの基本

JavaScriptは世界で最も普及しているプログラミング言語です1

JavaScriptは強力なプログラミング言語であり、Webサイトに対話操作を追加することができます。 ブレンダン・アイク (Brendan Eich) によって考案されました。

JavaScript は汎用性が高く、初心者にもやさしいものです。経験を積めば、ゲーム、 2D や 3D のアニメーション、包括的なデータベース駆動型のアプリなどが作れるようになります。

JavaScript は比較的コンパクトですが、一方でとても柔軟性があります。開発者は JavaScript 言語のコアをベースに多種多様なツールを作成し、最小限の労力で膨大な様々な機能を利用できるようにしました。例えば以下のようなものがあります。

  • ブラウザーのアプリケーションプログラミングインターフェイス (API)。Webブラウザーに組み込まれた API により、動的な HTML の作成、 CSS スタイルの設定、ユーザーのWebカメラからの動画ストリームの収集や操作、三次元グラフィックや音声サンプルの生成などの機能を提供します。
  • 開発者が他のコンテンツプロバイダーのサイト(Twitter や Facebook など)から機能を組み込むことを可能にする、サードパーティの API。
  • すばやくサイトやアプリケーションを構築することができ、 HTML に組み込み可能なサードパーティのフレームワークやライブラリー。

コアの JavaScript 言語が上記のツールとどのように違うのか、その詳細を紹介することは、 JavaScript の軽い入門者向けの書籍であるこの記事の範囲外です。詳細は MDN の JavaScript 学習領域や、 MDN の他の部分で詳しく学ぶことができます。

以下では、コア言語のいくつかの側面について紹介します。またブラウザーの API 機能についてもいくつか説明します。楽しみましょう!

"Hello world!" の例

JavaScript は、最も人気のある現代のWeb技術のひとつです。 JavaScript のスキルが上がれば、Webサイトのパワーと創造性は新たな次元に入るでしょう。

しかし、 JavaScript を使いこなせるようになるのは HTML や CSS よりも少し難しいです。小さなものから始め、小さく確実な手順で作業を続ける必要があるかもしれません。始めるにあたって、"hello world!" を表示する例(基本的なプログラミング例の標準)を作りながら、基本的な JavaScript をページに追加する方法を紹介しましょう。

  1. 最初にテストサイトに行き、 scripts という名前の新しいフォルダーを作成してください。それから、この scripts フォルダーの中に main.js という新しいファイルを作成して保存してください。

  2. index.html ファイルの </body> 終了タグの直前に新しい行で、以下の新しい要素を追加してください。

    <script src="scripts/main.js"></script>
    
  3. これは CSS の <link> 要素の時の作業と基本的に同じです。これは JavaScript をページに適用するので、(CSS の時と同じく、ページ上の何に対しても) HTML に影響を与えることができます。

  4. main.js ファイルに次のコードを追加してください。

    const myHeading = document.querySelector("h1");
    myHeading.textContent = "Hello world!";
    
  5. 最後に、 HTML と JavaScript を書いたファイルを保存したことを確認し、ブラウザーで index.html を読み込んでください。

"hello world" の見出しが firefox のロゴの上にある

Note 上記の説明で <script> 要素を HTML ファイルの末尾付近に置いたのは、ブラウザーがファイルに現れる順番でコードを読み込むからです。

JavaScript が先に読み込まれ、まだ読み込まれていない HTML に影響を与えることになると、問題が生じる可能性があります。 JavaScript を HTML ページの下部に配置することは、この依存関係に対応する一つの方法です。その他の方法については、スクリプトの読み込み方針をご覧ください。

何が起きたのか

JavaScript を使用して、見出しの文字列が Hello world! に変更されました。最初に document.querySelector() 関数を使用して見出しを選択し、 myHeading と呼ばれる変数に格納しています。これは CSS のセレクターを使用するのととてもよく似ています。要素に対して何かをしたくなったら、まずその要素を選択する必要があります。

その後、 myHeading 変数の textContent プロパティ(見出しの内容を表す)の値を Hello world! に設定します。

Note 上の例で使用した機能はどちらもドキュメントオブジェクトモデル (DOM) API の一部であり、これを使って文書を操作することができます。

言語の短期集中コース

どのように動作するかをよりよく理解できるように、 JavaScript 言語の基本機能のいくつかを説明しましょう。これらの機能はすべてのプログラミング言語に共通しているので、これらの基本をマスターすれば、ほとんど何でもプログラムできるようになります!

Note この記事では、 JavaScript コンソールにサンプルコードを入力して、何が起こるのかを確認してみます。 JavaScript コンソールの詳細については、開発者ツールに慣れる (Firefoxの場合は ブラウザー開発ツールを探る)を参照しましょう。

変数

変数は、値を格納できる入れ物です。まず、 let というキーワードと、その後に任意の名前を指定することで、変数を宣言します。

let myVariable;

Note 行末のセミコロンは文が終わる場所を示します。単一の行で複数の文を区切る場合には絶対に必要です。しかし、個々の文の末尾に置くことが良い習慣だと信じている人もいます。使用する場面と使用しない場合については他のルールもあります。詳しくは Your Guide to Semicolons in JavaScript を参照してください。

Note 変数にはほとんど何でも名前を付けることができますが、いくらかの制約があります(変数の命名規則についてはこの記事を参照してください)。自信がない場合は、有効かどうか変数名を調べることができます。

Note JavaScript は大文字と小文字を区別します。 myVariablemyvariable とは異なる変数です。コードで問題が発生している場合は、大文字・小文字をチェックしてください。

変数を宣言したら、以下のように値を割り当てることができます。

myVariable = "Bob";

好みに応じて、両方の操作を同一の行で行うことができます。

let myVariable = "Bob";

変数の値は、名前で呼び出すだけで取得することができます。

myVariable;

変数に値を代入した後で、変更することもできます。

let myVariable = "Bob";
myVariable = "Steve";

なお、変数は様々なデータ型の値を保持することもできます。

変数 説明
文字列 一連のテキストで、文字列と呼ばれます。値が文字列であることを示すには、単一引用符または二重引用符で囲む必要があります。 let myVariable = 'Bob'; または
let myVariable = "Bob";
数値 数値です。数値は引用符で囲みません。 let myVariable = 10;
論理型 論理値です。これは真か偽かの値です。 truefalse は特別なキーワードで、引用符は必要ありません。 let myVariable = true;
配列 単一の参照で複数の値を格納できる構造です。 let myVariable = [1,'Bob','Steve',10];
配列の各メンバーは次のように参照します。
myVariable[0], myVariable[1], など。
オブジェクト 基本的には何でも格納できます。 JavaScript のすべてがオブジェクトであり、変数に格納することができます。学ぶ際にはこれを覚えておいてください。 let myVariable = document.querySelector('h1');
上記のすべての例も同様です。

ではなぜ変数が必要なのでしょうか。何か面白いプログラミングをするには変数が必要です。値が変更できなければ、挨拶のメッセージをパーソナライズしたり、画像ギャラリーに表示されている画像を変更するなどの動的な操作ができないのです。

コメント

コメントは、ブラウザーから無視される、コードの間に入れられた短いテキストスニペットです。CSS と同じように、JavaScript のコードではコメントを付けることができます。

/*
挟まれているすべてがコメントです。
*/

コメントに改行が含まれていない場合、次のように 2 つのスラッシュの後ろに記載する方が簡単です。

// これはコメントです

演算子

演算子は、2 つの値 (または変数) に基づいて結果を生成する数学的な記号です。次の表では、JavaScript コンソールで試してみるいくつかの例とともに、最も単純な演算子をいくつか見ることができます。

演算子 説明 記号
加算 2 つの数値を足し合わせたり、 2 つの文字列を結合したりします。 + 6 + 9;
'Hello ' + 'world!';
減算、乗算、除算 基本的な数学の計算を実施します。 -, *, / 9 - 3;
8 * 2; // JS での乗算はアスタリスク
9 / 3;
代入 すでに出てきました。変数に値を割り当てます。 = let myVariable = 'Bob';
厳密等価 これは、2 つの値が等しく、かつデータ型が同じであるかどうかを調べます。 true/false (論理値)の結果を返します。 === let myVariable = 3;
myVariable === 4;
否定、非等価 その後にあるものと論理的に反対の値を返します。たとえば truefalse に換えます。等価演算子と一緒に使用されると、否定演算子は 2 つの値が等しくないかどうかを調べます。 !, !==

「否定」の場合は次の通りです。基本の式が true であれば、反転するので比較結果は false となります。

let myVariable = 3;
!(myVariable === 3);

「非等価」は異なる構文ですが、基本的に同じ結果になります。ここでは「myVariable が 3 と等しくない」ことを調べます。次の例では false を返します。 myVariable は 3 と等しいからです。

let myVariable = 3;
myVariable !== 3;

他にも演算子はもっとたくさんありますが、今のところはこれで十分です。全体の一覧については、式と演算子を参照してください。

Note データ型を混在させると、計算を実行するときに奇妙な結果になる可能性があるため、変数を正しく参照し、期待通りの結果を得るように注意してください。例えばコンソールに '35' + '25' と入力してみてください。期待通りの結果にならないのはなぜでしょうか。引用符は数字を文字列に変換するので、数字を加算するのではなく、文字列を連結する結果になったのです。 35 + 25 を入力すれば、正しい結果が得られます。

条件分岐

条件分岐は、ある式が true を返すかどうかをテストし、その結果次第でそれぞれのコードを実行するコード構造です。条件分岐のよくある形は if...else 文です。例えば以下の通りです。

let iceCream = "チョコレート";
if (iceCream === "チョコレート") {
  alert("やった!チョコレートアイス大好き!");
} else {
  alert("あれれ、でもチョコレートが好きなのに......");
}

if () の中の式が条件です。ここでは等価演算子を使用して、変数 iceCreamチョコレートという文字列を比較し、2 つが等しいかどうかを調べています。この比較が true を返した場合、コードの最初のブロックが実行されます。比較が真でない場合、最初のブロックはスキップされ、 else 文の後にある 2 番目のコードブロックが代わりに実行されます。

関数

関数は、再利用したい機能をパッケージ化する方法です。プロシージャが必要なときは、毎回コード全体を書くのではなく関数名を使って関数を呼び出すことができます。すでにいくつかの関数の仕様を見てきました。例えば次のようなものです。

let myVariable = document.querySelector("h1");
alert("hello!");

これらの関数、 document.querySelectoralert は、必要なときにいつでも使えるようブラウザーに組み込まれています。

もし変数名に見えるものがあったとしても、その後に括弧 () が付いていれば、おそらくそれは関数です。関数は普通、仕事をするのに必要な小さなデータである引数を取ります。引数は括弧の中に入れ、複数の引数がある場合はカンマで区切ります。

例えば、 alert() 関数はブラウザーのウィンドウにポップアップボックスを表示しますが、ポップアップボックスに何を書き込むかを関数に指示するために、文字列を引数として渡す必要があります。

嬉しいことに、自分で関数を定義することができます。次の例では、引数として 2 つの数値をとり、それらを乗算するという単純な関数を記載します。

function multiply(num1, num2) {
  let result = num1 * num2;
  return result;
}

上記の関数をコンソールで実行し、いくつかの引数を指定してテストしてみてください。例えば次のようなものです。

multiply(4, 7);
multiply(20, 20);
multiply(0.5, 3);

Note return 文は result の値を関数内から関数の外に戻すことをブラウザーに指示し、それを利用できるようにします。これが必要な理由は、関数内で定義された変数が、その関数内でしか利用できないためです。これは変数のスコープと呼ばれています(変数のスコープのより詳しい説明をお読みください)。

イベント

Webサイトを本当にインタラクティブにするには、イベントが必要です。イベントは、ブラウザーの中で起きていることを検出し、その応答としてコードを実行するコード構造です。最も分かりやすい例は click イベントで、マウスで何かをクリックするとブラウザーによって発行されるものです。これを実行するには、コンソールに以下のように入力してから、現在のWebページ上をクリックしてください。

document.querySelector("html").addEventListener("click", function () {
  alert("痛っ! つつかないで!");
});

要素にイベントハンドラーを取り付ける方法はいくつもあります。ここでは <html> 要素を選択しています。そして、addEventListener() 関数を呼び出し、待ち受けるイベントの名前 ('click') とイベントが発生したときに実行する関数を渡します。

先ほど addEventListener() に渡した関数は、名前を持たないので無名関数と呼ばれます。無名関数の書き方として、アロー関数と呼ばれるものがあります。アロー関数は () =>function () の代わりに使用します。

document.querySelector("html").addEventListener("click", () => {
  alert("痛っ! つつかないで!");
});

Webサイトの例を膨らませる

さて、 JavaScript の基本のおさらいが終わったところで、例題のサイトに新しい機能を追加してみましょう。

先に進む前に、 main.js ファイルの現在の内容を削除して、空のファイルを保存してください。そうしないと、 "Hello world!" の例で使用した既存のコードが、これから追加する新しいコードと衝突してしまいます。

画像の切り替えの追加

このセクションでは、 DOM API 機能をもっと使用して、サイトに画像を追加しましょう。画像をクリックすると JavaScript を使用して 2 つの画像を切り替えることができます。

  1. まずサイトに掲載したいと思う別な画像を見つけてください。最初の画像と同じサイズか、できるだけ近いものを使用してください。

  2. この画像を images フォルダーに保存してください。

  3. この画像の名前を firefox2.png に変更してください。

  4. main.js ファイルに次の JavaScript を入力してください。

    const myImage = document.querySelector("img");
    
    myImage.onclick = () => {
      const mySrc = myImage.getAttribute("src");
      if (mySrc === "images/firefox-icon.png") {
        myImage.setAttribute("src", "images/firefox2.png");
      } else {
        myImage.setAttribute("src", "images/firefox-icon.png");
      }
    };
    
  5. index.html をブラウザーに読み込みます。画像をクリックすると、もう一方の画像に変わるでしょう。

何が起こったのでしょうか。<img> 要素への参照を変数 myImage に格納しました。次に、この変数の onclick イベントハンドラープロパティに、名前のない関数(「無名」関数)を代入しました。そうすれば、この要素がクリックされるたびに次の動きをします。

  1. 画像の src 属性の値を取得します。

  2. 条件分岐を使って、src の値が元の画像のパスと等しいかどうかをチェックします。

    1. そうであれば、src の値を 2 番目の画像へのパスに変更し、もう一方の画像が強制的に <img> 要素の中に読み込まれるようにします。
    2. そうでない(すでに変更されている)場合、src の値を元の画像のパスに戻して、元の状態に戻ります。

パーソナライズされた挨拶メッセージの追加

次に、もう 1 つの小さなコードを追加し、ユーザーがサイトにアクセスしたときに、ページの表題をパーソナライズされた挨拶メッセージに変更してみましょう。この挨拶メッセージは、ユーザーがサイトを離れて後で戻った時にも保存されるようにします。Web Storage API を使用して保存しましょう。したがって、必要な時にいつでもユーザーと挨拶メッセージを変更できるオプションも用意しましょう。

  1. index.html では、 <script> 要素の直前に次の行を追加します。

    <button>ユーザーを変更</button>
    
  2. main.js では、次のコードを下記のとおりにファイルの最後に配置します。これは新しいボタンと見出しへの参照を変数に格納します。

    let myButton = document.querySelector("button");
    let myHeading = document.querySelector("h1");
    
  3. パーソナライズされた挨拶を設定する以下の関数を追加しましょう。まだ何も起こりませんが、すぐに修正します。

    function setUserName() {
      const myName = prompt("あなたの名前を入力してください。");
      localStorage.setItem("name", myName);
      myHeading.textContent = `Mozilla is Cool, ${myName}`;
    }
    

    setUserName() 関数では、prompt() 関数を使用して、alert() のようにダイアログボックスを表示しています。しかし、prompt()alert() とは異なり、ユーザーにデータを入力するよう求め、ユーザーが OK を押した後に変数にそのデータを格納します。この場合、ユーザーに名前を入力するよう求めます。次に、localStorage と呼ばれる API を呼び出すことで、ブラウザーにデータを格納して後で受け取ることができます。 localStorage の setItem() 関数を使って、'name' と呼ばれるデータを作成し、 myName に入っているユーザーから入力されたデータを格納します。最後に、見出しの textContent に文字列と新しく格納されたユーザーの名前を設定します。

  4. 以下のような条件ブロックを追加します。最初に読み込んだときにアプリを構造化するので、これを初期化コードと呼ぶこともできます。

    if (!localStorage.getItem("name")) {
      setUserName();
    } else {
      const storedName = localStorage.getItem("name");
      myHeading.textContent = `Mozilla is Cool, ${storedName}`;
    }
    

    このブロックでは、最初に name のデータが存在しているかどうかをチェックするために否定演算子(! で表される論理否定)を使用しています。存在しない場合は、作成するために setUserName() 関数が実行されます。存在する場合は(つまり、以前の訪問時にユーザーが設定した場合)、 getItem() を使用して格納された名前を受け取り、 setUserName() の中で行ったのと同様に、見出しの textContent に文字列とユーザーの名前を設定します。

  5. 最後に、以下の onclick イベントハンドラーをボタンに設定します。クリックすると、setUserName() 関数が実行されます。これでユーザーがボタンを押すことで、好きな時に新しい名前を設定できるようになります。

    myButton.onclick = () => {
      setUserName();
    };
    

ユーザー名か null か

この例を実行してユーザー名を入力するダイアログボックスが出たとき、キャンセルボタンを押してみてください。結果として "Mozilla is cool, null" というタイトルが表示されるでしょう。これはプロンプトをキャンセルしたときに、値が null、つまり値がないことを示す JavaScript の特殊な値に設定されるためです。

また何も入れずに OK を押してみてください。結果として "Mozilla is cool," というタイトルが表示され、これは理由が明白です。

この問題を避けるには、ユーザーが null や空白の名前を入力していないかチェックするよう、setUserName() 関数を書き換えます。

function setUserName() {
  const myName = prompt("あなたの名前を入力してください。");
  if (!myName) {
    setUserName();
  } else {
    localStorage.setItem("name", myName);
    myHeading.textContent = `Mozilla is Cool, ${myName}`;
  }
}

人間の言葉で言うと、 myName に値がない場合や、nullの場合、 最初から setUserName() を実行します。値がない場合(上記の式が真でない場合)には、localStorage に値を設定して、見出しのテキストにも設定します。

まとめ

最後までこの記事の手順に従った場合は、最終的に次のようなページが表示されているでしょう。

ヘッダー、中央の大きなロゴ、内容、ボタンなどの要素を作成した後の HTML ページの最終的な外観

もし途中で行き詰まってしまったら、「サンプルコード」と見比べてみましょう。

Web

WebとWebブラウザーについてまとめます。といっても、仕組みがわかると面白いかも、くらいの気持ちで気楽にいきましょう。

Webとは

"This is for everyone"

Tim Berners-Lee (@timberners_lee)

Webは情報共有とコミュニケーションのためのプラットフォームです。 Web上ではソーシャルメディア、ビデオストリーミング、オンラインショッピングなど様々な活動が行われます。(便利ですよね。)

World Wide Web

― 画像: https://worldwideweb.cern.ch/browser/ より

これは世界初のWebブラウザーWorldWideWebの画像です。

World Wide Web (Web) は、1989年に分散型ハイパーテキストシステム (distributed hypertext system)としてティム・バーナーズ・リーによって提案されたアイデアが元になっています。世界中に張り巡らされた蜘蛛の巣を連想して名付けられました。

Note
中央集権型 (centralized) と 非中央集権型 (decentralized) と 分散型 (distributed)


― 画像: ポール・バラン (1964) On Distributed Communications Networks より

Webは分散型のシステムです。中央集権型のシステムではありません。Web上で何か活動するとき、中央の機関からの許諾は一切必要ありません。いつでも、どこでも、誰でも自由に使うことができます。

Webブラウザー

Webブラウザーは、Webページの取得・描画を行うソフトウェアです。

代表的なWebブラウザーとしては、Google ChromeSafariMozilla FirefoxMicrosoft Edgeなどが挙げられます。

Webの標準化

主に3つの標準化団体が関わっています。

IETFはインターネットに関する全般的な技術、約束事、コミュニティで共有すべき事柄の管理を担っています。それらは RFC (Request for Comments) と呼ばれる形式で記録されています。

W3CとWHATWGはWebに関する仕様の管理を担っています。具体的にはW3CはCSSなど、WHATWGはHTML関連の仕様などを発行しています。 WHATWGの発行している仕様はIETFやW3Cの仕様とは異なり内容が確定することはありません。HTML Living Standardはその時点が常に最新版の標準仕様となっており、継続的に更新され続けています。

いずれの仕様もWeb上で公開されており、無償で閲覧可能、誰でも参加可能、自由に実装可能です。

ポイント

  • Web … 分散型ハイパーテキストシステム
  • Webブラウザー … Webページの取得・描画を行うソフトウェア
  • Webの標準化 … 無償で閲覧可能、誰でも参加可能、自由に実装可能

Webの仕組み

Webの誕生から現在に至るまでWeb上で出来ることやその役割は大きく変わりました。 しかし、それを支える基本的な仕組みと構成要素は実はあまり変わっていません。

Webはこれらの要素に支えられています。

  • URL … インターネット上のリソースの位置を特定するための識別子
  • HTTP … Webの転送用のプロトコル
  • コンテンツ … Webページなど

Note
変わり続けるルール

多くのルールを覚えることは決して重要ではありません。 なぜなら現実の問題は複雑でそれに合わせてルールも変わり続けていくものだからです。 大切なのは解決したい問題への理解を深めていくことなのです。 何を解決するためのルールなのか一緒に考えていきましょう。(この後も退屈な説明が続きますがどうかお付き合いください。)

例えばこれらの仕様はいずれも常に最新版の標準仕様となっており継続的に更新され続けています。

Webページ


― 画像: JavaScript とは - Web開発を学ぶ | MDN より

Webページはこれらの要素に支えられています。

  • HTML … Webページの構造を記述するための言語
  • CSS … Webページの見た目を記述するための言語
  • JavaScript … プログラミング言語

ポイント

  • Web … URL/HTTP/コンテンツ
  • Webページ … HTML/CSS/JavaScript

参考文献

URL - Uniform Resource Locator

URLはインターネット上のリソースの位置を特定するための文字列です。 住所と似ています。

URLの仕様からいくつか具体例を挙げます。

例:

https://example.com/
https://localhost:8000/search?q=text#hello
urn:isbn:9780307476463
file:///ada/Analytical%20Engine/README.md

これらはいずれもURLです。

URLを使ってリンクさせることができます。

ユニフォーム (uniform) と名前にあるのは、統一的なルールがあります、ということです。 Web上で「〇〇にアクセスしたい」と思ったときみんなで使える同じ表現があったほうが便利というわけですね。

ではURLにはどういうルールがあるのか詳しく見ていきましょう。

スキーム (Scheme)

URLの種別や性質を意味します。

https://example.com/

この例でいうと、先頭から : までの文字列 https が「スキーム」です。住所の例で言うと、郵便を表す記号「〒」の役割と似ています。URLはスキームごとにその書式が異なります。

Note
インターネット上で利用可能なURLスキームの一覧

Uniform Resource Identifier (URI) Schemes

インターネット上で利用可能なURLスキームの一覧はIANA (Internet Assigned Numbers Authority)によって管理されています。

https スキームは Hypertext Transfer Protocol Secure (RFC 9110) を意味します。その後に文字列 :// が続きます。

https スキームのURLの場合は、その後に「ホスト (Host)」「ポート (Port)」「パス (Path)」「クエリー (Query)」「フラグメント (Fragment)」と続きます。

Note
httphttps

前者は "Hypertext Transfer Protocol"、後者は "Hypertext Transfer Protocol Secure" を意味するスキームです。 "Secure" と付いているのは、必ず TLS (Transport Layer Security) の上でやり取りを行います、という意味です。 最近 http://... から始まるURLはあまり見かけないかと思います。 これはHTTPのセキュリティとプライバシーの問題が広く知られ、代わりにHTTP over TLSが使われるようになったためです。 TLSを使うことによってクライアント・サーバー間の通信が暗号化され、もし仮に傍受されても第三者による改ざんや解析は以前より難しくなりました。

ホスト (Host)

郵便番号と住所みたいなものです。「ポスト」じゃないですよ。

https://example.com/

この例でいうと、example.com の部分が「ホスト」です。 ホストはドメイン名またはIPアドレスです。 ドメイン名を見かけることが多いかと思います。

Note
ドメイン名

インターネットに接続しているすべてのコンピューターにはIPアドレスが割り当てられています。 ドメイン名はそうしたIPアドレスに人間が読めるように別の名前を付けたものです。 ドメイン名は Domain Name System (DNS) によって支えられています。 Internet Corporation for Assigned Names and Numbers (ICANN) を中心とした複数のドメイン管理事業者によって管理されており、世界中で使うことができるようになっています。

例: Google Public DNS に example.com を問い合わせる例

"Answer": [
  {
    "name": "example.com.",
    "type": 28 /* AAAA */,
    "TTL": 13460,
    "data": "2606:2800:220:1:248:1893:25c8:1946"
  }
]

ドメイン名 example.com はIPアドレス [2606:2800:220:1:248:1893:25c8:1946] の別名ですよ、という意味です。

ポート (Port)

ポート」が書いてあるURLは普段あまり見かけないかもしれませんね。 でもインターネット上で通信するとき必ず登場します。存在するからには一応紹介しておきます。

ホストの後にはポートを書くことができます。 ホストと : 文字の後にポート番号を書きます。 省略すると https スキームの場合は 443 が割り当てられています。

例えばこれらのURLは同じ意味です。

https://example.com/
https://example.com:443/

この場合どちらも 443 ポートを意味します。

オリジン (Origin)

スキーム・ホスト・ポートをまとめて扱うことがあります。 具体的にはセキュリティ上の理由から送信元の同一性を判定するケースです。 このとき使われるのが「オリジン」です。

https://localhost:8000/search?q=text#hello

例えばこの例では (https, localhost, 8000) の3つの組がオリジンです。 オリジンは https://localhost:8000 のように表現します。

JavaScriptでは location.origin でオリジンを取得できます。

Note
Webブラウザーのセキリティ機構

Webブラウザーには同一オリジンポリシーと呼ばれる保護機構があり、オリジン間のアクセスは原則禁止されています。 異なるオリジン間でのアクセスを許可するには、オリジン間リソース共有 (Cross-Origin Resource Sharing, CORS) の仕組みを使います。 CORSはリソースを提供する人が同一オリジンポリシーを緩和しオリジン間のアクセスを許可するための仕組みです。

パス (Path)

/ 文字で区切られた文字列が続きます。これが「パス」です。ホストの中のリソースの場所を意味します。 / は日本語でいう「の」みたいなものです。 階層構造を表現します。

https://example.com/

この場合パスは / です。

https://example.com/foo/bar

この場合パスは /for/bar です。

ちなみにJavaScriptでは location.pathname でパスを取得できます。

クエリー (Query)

? 文字で区切られた文字列が続くことがあります。場合によっては =& が含まれます。これは「クエリー」です。

https://localhost:8000/search?q=text#hello

例えばこの例では q=text がクエリーです。 = は日本語でいう「は」みたいなものです。

Google検索の例: https://www.google.com/search?q=answer+to+life+the+universe+and+everything

この場合クエリーは q=answer+to+life+the+universe+and+everything です。 q は "answer to life the universe and everything" ですよ、という意味です。

JavaScriptでは location.search でクエリーを取得できます。

フラグメント (Fragment)

# 文字で区切られた文字列が続くことがあります。これは「フラグメント」です。 URLの末尾にフラグメントがあるとき、そのリソースの中の一部分フラグメントを意味します。 HTMLの場合はフラグメントと id 属性の名前が一致するときその箇所を指定することができます。

https://localhost:8000/search?q=text#hello

例えばこの例では hello がフラグメントです。

JavaScriptでは location.hash でフラグメントを取得できます。

ポイント

  • URLはインターネット上のリソースの位置を特定するための識別子
  • https:// から始まるURLは https スキームのURL
  • https スキームのURLの構成要素 … ホスト、ポート、パス、クエリー、フラグメント

HTTP - Hypertext Transfer Protocol

HTTPはWebの転送用のプロトコルです。

URLがあればそのリソースがWeb上の「どこに」あるか知ることができます。 ではそのリソースには「どのように」アクセスしたらよいのでしょうか。

https スキームや http スキームのURLに対応するリソースにアクセスする手順プロトコル、それがHTTPです。

プロトコル

― この画像は © 2012 Karl Dubost クリエイティブ・コモンズ CC BY 3.0 ライセンスのもとに利用を許諾されています。

二者間でのコミュニケーションが成立するためには3つの要素が含まれています。

  • シンタックス (コードの文法)
  • セマンティクス (コードの意味)
  • タイミング (速度合わせと順序付け)

「挨拶」を例に考えてみましょう。 腰を曲げるジェスチャー、これはお辞儀のためのシンタックスです。日本ではそういう慣習ですね。お辞儀をすることで「どうも、こんにちは」という意味づけが行われます。これはセマンティクスです。二者間で特定のタイミングでこれらが発生したとき、一連の出来事として成立します。どちらもお辞儀をし、お互いに理解することによって「挨拶」として成立した、となるわけです。

Web上でのやり取りも同じです。 HTTPはサーバー・クライアントの二者関係で行われます。 クライアントはサーバーに対して要求リクエストを送り、クライアントからの要求リクエストを受け取るとサーバーは応答レスポンスを返します。

HTTPの仕様にある具体例を挙げます。 次のようなコードの送受信を行います。

クライアントリクエスト (クライアント側からサーバー側への送信):

GET /hello.txt HTTP/1.1
User-Agent: curl/7.64.1
Host: www.example.com
Accept-Language: en, mi

サーバーレスポンス (サーバー側からクライアント側への送信):

HTTP/1.1 200 OK
Date: Mon, 27 Jul 2009 12:28:53 GMT
Server: Apache
Last-Modified: Wed, 22 Jul 2009 19:15:56 GMT
ETag: "34aa387-d-1568eb00"
Accept-Ranges: bytes
Content-Length: 51
Vary: Accept-Encoding
Content-Type: text/plain

Hello World! My content includes a trailing CRLF.

構成要素は4つ。

  • リクエストライン (Request Line)
  • フィールド (Fields)
  • ステータスコード (Status Codes)
  • コンテンツ (Content)

詳しく見ていきましょう。

リクエストライン (Request Line)

クライアントリクエストの1行目の GET /hello.txt HTTP/1.1 の部分は、リクエストライン (Request Line) と呼ばれます。どこに、どのような方法メソッドでアクセスしたい、とサーバーに伝えるためのものです。

クライアントリクエスト:

GET /hello.txt HTTP/1.1

この例はURL http://www.example.com/hello.txt にアクセスするためのクライアントリクエストです。GET メソッドでパス /hello.txt へのアクセスを要求しています。

GET メソッドは取得するために使われる最も基本的なメソッドで、リンクをクリックしたときやWebブラウザーのアドレスバーにURLを入力したとき送信されます。Webでのやり取りはこのリクエストラインで始まる文字列をWebサーバーに伝えるところから始まります。

Note
HTTP/1.1 と HTTP/2

HTTP/1.1は1995年に公開され、2022年に最新版に改定されました。 HTTP/1.1は現在も使われ続けています。 一方、HTTP/2は2022年に公開されました。 HTTP/2はHTTP/1.1とは異なり複数のメッセージを同時に扱える、コンピューターにとってより効率的な形式のシンタックスが特徴の新しい仕様です。 HTTP/2ではリクエストラインの代わりに一貫してフィールドを使うなどHTTP/1.1と文法が大きく異なりますがその意味は全く変わりません。

HTTP/2 仕様のリクエストの例:

  GET /resource HTTP/1.1           HEADERS
  Host: example.org          ==>     + END_STREAM
  Accept: image/jpeg                 + END_HEADERS
                                       :method = GET
                                       :scheme = https
                                       :authority = example.org
                                       :path = /resource
                                       host = example.org
                                       accept = image/jpeg

フィールド (Fields)

: 文字で区切られた行が続きます。これは「フィールド (Fields)」です。リクエストとレスポンスに関連する付帯情報を意味します。

Host: www.example.com

例えばこの場合、送信先 Host (ホスト) は www.example.com ですよ、という意味です。

ステータスコード (Status Codes)


― 画像: HTTP Cats より

「ステータスコード (Status Codes)」はそのリソースの存在やアクセス可否などをサーバーが伝えるためのものです。 サーバーはレスポンスを返すとき、最初にステータスコードを返します。

サーバーレスポンス:

HTTP/1.1 200 OK

この例ではステータスコード 200 を返しています。 ステータスコードは100〜599までの3桁の整数で表されます。 レスポンスはステータスコードの100の位で大きく分類されます。

  • 1xx (情報): リクエストを受信しました。プロセスを続行します。
  • 2xx (成功): リクエストは正常に受信、理解され、受け入れられました。
  • 3xx (リダイレクト): リクエストを完了するにはさらにアクションを実行する必要があります。
  • 4xx (クライアントエラー): リクエストに不正な構文が含まれているか、リクエストを実行できません。
  • 5xx (サーバーエラー): サーバーは有効なリクエストを実行できません。

Note
418 I'm a teapot

私はティーポットなのでコーヒーを入れることを拒否しました、という意味のステータスコードです。 1998年のエイプリルフールに公開されました。 現在でもステータスコード 418IANA HTTP Status Code Registry によって管理されています。

コンテンツ (Content)

フィールドが終わり「コンテンツ (Content)」が続きます。 コンテンツはHTML、画像、動画、あらゆるデータです。

ポイント

  • HTTPはWebの転送用のプロトコル
  • HTTPはクライアントからのリクエストとサーバーからのレスポンスによってやり取りを行う
  • HTTPの構成要素 … リクエストライン/フィールド/ステータスコード/コンテンツ

HTML

HTMLはWebページの構造を記述するための言語です。

「どこに」「どのように」アクセスするかというと、Webでは「URLに」「HTTPで」アクセスするわけですね。 では一体「何を」Webブラウザーは見せているのでしょうか。 それは「HTML」です。(この入門ガイドもそうですよ。)

もともとHTMLは主に科学文書の意味や構造を正確に記述するための言語として設計されました。 現在では、あらゆる文書やアプリの記述に応用されています。

文法と意味

HTMLはマークアップ言語 (Markup Language)と呼ばれるカテゴリーの言語です。 HTMLの仕様から具体的なコードの例を挙げます。

例:

<!DOCTYPE html>
<html lang="en">
 <head>
  <title>Sample page</title>
 </head>
 <body>
  <h1>Sample page</h1>
  <p>This is a <a href="demo.html">simple</a> sample.</p>
  <!-- this is a comment -->
 </body>
</html>

「タグ (Tag)」と呼ばれるマークでコンテンツのかたまりを囲みますマークアップします。 このかたまりは「要素 (Element)」と呼ばれます。


― 画像: 「HTML の基本」より

要素の中に別の要素を含めることもあります。

<p>This is a <a href="demo.html">simple</a> sample.</p>

この例では<p>: 段落要素の中に<a>: アンカー要素が含まれています。 リンクが含まれている文、その文を含む段落、という構造なわけです。

やってみよう!

基本的なルールが分かってきたところで、さっそく遊んでみましょう!

<p>ここは段落なのですよ。</p>

<p>HTMLを使えばインターネット上のあらゆるコンテンツに<a href="https://kou029w.github.io/intro-to-web-dev/web/html.html">リンク</a>できるのです。</p>

MDNで調べてみよう

MDN (MDN Web Docs) は、HTML、CSS、JavaScriptなどWeb技術に関するあらゆる文書を網羅的にまとめているサイトです。オープンソースで提供されており、誰でも自由に貢献することができます。MDNにアクセスすればWebブラウザーに組み込まれているあらゆるAPIの仕様やその機能を調べることができます。

Googleなどの検索エンジンで「MDN [調べたいキーワード]」または「site:developer.mozilla.org [調べたいキーワード]」を検索してみましょう。

ポイント

  • MDN … Webブラウザーに組み込まれているAPIの仕様や機能を調べることができる

API - Application Programming Interface

システムには情報やエネルギーなど外部とのやりとりするための境界面があり、それを「インターフェース」と呼びます。

API (Application Programming Interface) とは、アプリケーションソフトウェアのインターフェースを指す概念です。

家電製品を例に考えてみましょう。 家電製品はそのシステムの外部から供給された電力を消費して仕事をします。 このとき外部との境界には外部から電力を供給するためのインターフェースが存在します。 それはコンセントですね。 コンセントには定格電圧や形状など規格があります。 インターフェースとはそういったルールのことです。 家電製品にはコンセントがあるので専門的な技能が無くても手軽に電気的エネルギーにアクセスできるのです。 これは物理的な例ですが、外部との境界にインターフェースがあるのはWebも同じです。 JavaScriptから簡単に外部と情報をやりとりしたり、外部のサービスの機能を使うためにAPIがあります。

参考文献

開発者ツールに慣れる

Webブラウザーには開発者ツールが内蔵されています。 これを使うことでWebブラウザーが表示しているHTMLの状態を調べたり、どのリソース (URL) に、どのようにアクセスしているのか (HTTPメッセージの内容) 知ることができます。

ここではGoogle ChromeやMicrosoft EdgeなどChromium系ブラウザーの開発者ツールの基本的な使い方を説明します。

開発者ツールの起動方法

開発者ツールを起動するにはいくつかの方法があります。

  • 右クリック > [検証] を選択
  • [その他のツール] > [デベロッパー ツール] を選択
  • Windows/Linuxの場合: Ctrl+Shift+I
  • macOSの場合: ⌘ (Command)+⌥ (Option)+I

どの方法でもOKです。

Note
開発者ツールの翻訳

はじめて開発者ツールを起動したとき、メニューがすべて英語で表示されることがあります。 開発者ツールのメニューを翻訳するには開発者ツール上部の [Always match Chrome's language] を選択しましょう。

実際に手元のWebブラウザーから開発者ツールを起動してみましょう。

要素 (Elements)

画面上に表示されているHTML要素とその状態を知ること、一時的に編集することができます。

コンソール (Console)

JavaScriptの実行と、エラーメッセージなど実行しているコードを解析するための情報を知ることができます。

ソース (Sources)

実行しているコードの表示と一時停止 (ブレークポイントの設定)、そのコードを解析することができます。

ネットワーク (Network)

WebブラウザーがアクセスしているURLとそのHTTPメッセージの内容知ることができます。

  • 上側のペイン: タイムライン
  • 左側のペイン: リクエストの一覧
  • 右側のペイン: (リクエストの一覧から選択) リクエストヘッダー・プレビュー・レスポンスなどHTTPメッセージの詳細

ヘッダー

URLとリクエストのメソッド、レスポンスのステータスコードなどHTTPメッセージの基本的な情報を知ることができます。

プレビュー

(表示可能であれば) そのコンテンツを表示します。

レスポンス

そのコンテンツの生のデータを表示します。

ポイント

  • 開発者ツール … Webブラウザーが表示しているHTMLの状態を調べたり、どのリソースに、どのようにアクセスしているのか知ることができる

やってみよう!

  • 実際に手元のWebブラウザーで開発者ツールを起動していくつかのWebページにアクセスしてみよう

JavaScript

JavaScript Primer > 基本文法 > JavaScriptとは

JavaScriptを学びはじめる前に、まずJavaScriptとはどのようなプログラミング言語なのかを紹介します。

JavaScriptは主にWebブラウザーの中で動くプログラミング言語です。 ウェブサイトで操作をしたら表示が書き換わったり、ウェブサイトのサーバーと通信してデータを取得したりと現在のウェブサイトには欠かせないプログラミング言語です。 このようなJavaScriptを活用してアプリケーションのように操作できるウェブサイトをWebアプリとも言います。

JavaScriptはWebブラウザーだけではなく、Node.jsというサーバー側のアプリケーションを作る仕組みでも利用されています。 また、デスクトップアプリやスマートフォンアプリ、IoT(Internet of Things)デバイスでもJavaScriptを使って動かせるものがあります。 このように、JavaScriptはかなり幅広い環境で動いているプログラミング言語で、さまざまな種類のアプリケーションを作成できます。

― この文章は © 2023 jsprimer project クリエイティブ・コモンズ CC BY 4.0 ライセンスのもとに利用を許諾されています。

続きは JavaScript Primer > 基本文法 > JavaScriptとは を参照しましょう。

歴史

JavaScriptは、1995年にブレンダン・アイクによって、当初Netscape Navigatorのためのスクリプト言語として開発されました。当時のWebは非常にシンプルで静的なものであり、動的なユーザーインタラクションはほとんどありませんでした。

そんな中、当時Netscape Communicationsで働いていたブレンダン・アイクは上司から新しいスクリプト言語を開発するよう依頼され、C、Java、Self、Schemeなどの既存のプログラミング言語の概念を取り入れつつ、わずか10日間で初期バージョンのJavaScriptを開発しました。

動的なユーザーインタラクションやサーバーへの非同期通信(Ajax)など現在では当たり前となっている多くの機能が初めてWebブラウザー上で可能となり、またその後のWebブラウザー以外の技術の発展にも大きな影響を与えました。

ポイント

  • ECMAScript仕様による標準化
  • 仕様は毎年更新されている

値の評価と表示

JavaScript Primer > 基本文法 > 値の評価と表示

値の評価とは、入力した値を評価してその結果を返すことを示しています。 たとえば、次のような値の評価があります。

  • 1 + 1 という式を評価したら 2 という結果を返す
  • bookTitle という変数を評価したら、変数に代入されている値を返す
  • const x = 1;という文を評価することで変数を定義するが、この文には返り値はない

この値の評価方法を確認するために、Webブラウザー(以下ブラウザ)を使ってJavaScriptを実行する方法を見ていきます。

― この文章は © 2023 jsprimer project クリエイティブ・コモンズ CC BY 4.0 ライセンスのもとに利用を許諾されています。

続きは JavaScript Primer > 基本文法 > 値の評価と表示 を参照しましょう。

ポイント

  • Webブラウザーの開発者ツールのコンソール上でJavaScriptコードを評価する方法

やってみよう!

  • 実際に手元のWebブラウザーでJavaScriptを実行してみよう

変数と宣言

JavaScript Primer > 基本文法 > 変数と宣言

プログラミング言語には、文字列や数値などのデータに名前をつけることで、繰り返し利用できるようにする変数という機能があります。

JavaScriptには「これは変数です」という宣言をするキーワードとして、 constletvarの3つがあります。

varはもっとも古くからある変数宣言のキーワードですが、意図しない動作を作りやすい問題が知られています。 そのためECMAScript 2015で、varの問題を改善するためにconstletという新しいキーワードが導入されました。

この章ではconstletvarの順に、それぞれの方法で宣言した変数の違いについて見ていきます。

― この文章は © 2023 jsprimer project クリエイティブ・コモンズ CC BY 4.0 ライセンスのもとに利用を許諾されています。

続きは JavaScript Primer > 基本文法 > 変数と宣言 を参照しましょう。

ポイント

  • constは、再代入できない変数を宣言できる
  • letは、再代入ができる変数を宣言できる

やってみよう!

// 真空の光速度 (m/s)
const c = 299792458;

// 時間 (s)
let t = 0;

// 光の速度は変わらない
// c = 42;

// 時間は変わる
t = 0.001;

document.body.textContent = `${t} 秒間に光の進む距離: ${c * t} m`;

データ型とリテラル

JavaScript Primer > 基本文法 > データ型とリテラル

JavaScriptは動的型付け言語に分類される言語であるため、静的型付け言語のような変数の型はありません。 しかし、文字列、数値、真偽値といった値の型は存在します。 これらの値の型のことをデータ型と呼びます。

データ型を大きく分けると、プリミティブ型オブジェクトの2つに分類されます。

プリミティブ型(基本型)は、真偽値や数値などの基本的な値の型のことです。 プリミティブ型の値は、一度作成したらその値自体を変更できないというイミュータブル(immutable)の特性を持ちます。 JavaScriptでは、文字列も一度作成したら変更できないイミュータブルの特性を持ち、プリミティブ型の一種として扱われます。

一方、プリミティブ型ではないものをオブジェクト(複合型)と呼び、 オブジェクトは複数のプリミティブ型の値またはオブジェクトからなる集合です。 オブジェクトは、一度作成した後もその値自体を変更できるためミュータブル(mutable)の特性を持ちます。 オブジェクトは、値そのものではなく値への参照を経由して操作されるため、参照型のデータとも言います。

データ型を細かく見ていくと、7つのプリミティブ型とオブジェクトからなります。

  • プリミティブ型(基本型)
    • 真偽値(Boolean): trueまたはfalseのデータ型
    • 数値(Number): 423.14159 などの数値のデータ型
    • 巨大な整数(BigInt): ES2020から追加された9007199254740992nなどの任意精度の整数のデータ型
    • 文字列(String): "JavaScript" などの文字列のデータ型
    • undefined: 値が未定義であることを意味するデータ型
    • null: 値が存在しないことを意味するデータ型
    • シンボル(Symbol): ES2015から追加された一意で不変な値のデータ型
  • オブジェクト(複合型)
    • プリミティブ型以外のデータ
    • オブジェクト、配列、関数、クラス、正規表現、Dateなど

プリミティブ型でないものは、オブジェクトであると覚えていれば問題ありません。

typeof演算子を使うことで、次のようにデータ型を調べることができます。

console.log(typeof true); // => "boolean"
console.log(typeof 42); // => "number"
console.log(typeof 9007199254740992n); // => "bigint"
console.log(typeof "JavaScript"); // => "string"
console.log(typeof Symbol("シンボル")); // => "symbol"
console.log(typeof undefined); // => "undefined"
console.log(typeof null); // => "object"
console.log(typeof ["配列"]); // => "object"
console.log(typeof { key: "value" }); // => "object"
console.log(typeof function () {}); // => "function"

プリミティブ型の値は、それぞれtypeof演算子の評価結果として、その値のデータ型を返します。 一方で、オブジェクトに分類される値は"object"となります。

配列([])とオブジェクト({})は、どちらも"object"という判定結果になります。 そのため、typeof演算子ではオブジェクトの詳細な種類を正しく判定することはできません。 ただし、関数はオブジェクトの中でも特別扱いされているため、typeof演算子の評価結果は"function"となります。 また、typeof null"object"となるのは、歴史的経緯のある仕様のバグ[^1]です。

このことからもわかるようにtypeof演算子は、プリミティブ型またはオブジェクトかを判別するものです。 typeof演算子では、オブジェクトの詳細な種類を判定できないことは、覚えておくとよいでしょう。 各オブジェクトの判定方法については、それぞれのオブジェクトの章で見ていきます。

― この文章は © 2023 jsprimer project クリエイティブ・コモンズ CC BY 4.0 ライセンスのもとに利用を許諾されています。

続きは JavaScript Primer > 基本文法 > データ型とリテラル を参照しましょう。

ポイント

  • プリミティブ型とオブジェクトがある
  • リテラルはデータ型の値を直接記述できる構文として定義されたもの
  • プリミティブ型リテラル
    • 真偽値 … true false
    • 数値 … 42 3.14159 など
    • 文字列 … "JavaScript" など
    • BigInt … 9007199254740992n など
    • null … null

コメント

JavaScript Primer > 基本文法 > コメント

コメントはプログラムとして評価されないため、ソースコードの説明を書くために利用されています。 この書籍でも、JavaScriptのソースコードを解説するためにコメントを使っていきます。

コメントの書き方には、一行コメントと複数行コメントの2種類があります。

― この文章は © 2023 jsprimer project クリエイティブ・コモンズ CC BY 4.0 ライセンスのもとに利用を許諾されています。

続きは JavaScript Primer > 基本文法 > コメント を参照しましょう。

ポイント

  • // 以降から行末までが一行コメント
  • /**/ で囲まれた範囲が複数行コメント

やってみよう!

// これは一行コメント

/*
   これは
    複数行
      コメント
 */

// JavaScriptを使えば…

// 自由にテキストを書き換えることもできます!
document.body.textContent = "JavaScriptの世界からこんにちは!✨";

演算子

JavaScript Primer > 基本文法 > 演算子

演算子はよく利用する演算処理を記号などで表現したものです。 たとえば、足し算をする + も演算子の一種です。これ以外にも演算子には多くの種類があります。

演算子は演算する対象を持ちます。この演算子の対象のことを被演算子(オペランド)と呼びます。

次のコードでは、+演算子が値同士を足し算する加算演算を行っています。 このとき、+演算子の対象となっている12という2つの値がオペランドです。

1 + 2;

このコードでは+演算子に対して、前後に合計2つのオペランドがあります。 このように、2つのオペランドを取る演算子を二項演算子と呼びます。

// 二項演算子とオペランドの関係
左オペランド 演算子 右オペランド

また、1つの演算子に対して1つのオペランドだけを取るものもあります。 たとえば、数値をインクリメントする++演算子は、次のように前後どちらか一方にオペランドを置きます。

let num = 1;
num++;
// または
++num;

このように、1つのオペランドを取る演算子を単項演算子と呼びます。 単項演算子と二項演算子で同じ記号を使うことがあるため、呼び方を変えています。

この章では、演算子ごとにそれぞれの処理について学んでいきます。 また、演算子の中でも比較演算子は、JavaScriptでも特に挙動が理解しにくい暗黙的な型変換という問題と密接な関係があります。 そのため、演算子をひととおり見た後に、暗黙的な型変換と明示的な型変換について学んでいきます。

演算子の種類は多いため、すべての演算子の動作をここで覚える必要はありません。 必要となったタイミングで、改めてその演算子の動作を見るのがよいでしょう。

― この文章は © 2023 jsprimer project クリエイティブ・コモンズ CC BY 4.0 ライセンスのもとに利用を許諾されています。

続きは JavaScript Primer > 基本文法 > 演算子 を参照しましょう。

ポイント

  • 演算子はよく利用する演算処理を記号などで表現したもの
  • 四則演算や論理演算などさまざまな種類の演算子がある
  • 演算子には優先順位が定義されており、グループ化演算子で明示できる

条件分岐

JavaScript Primer > 基本文法 > 条件分岐

この章ではif文やswitch文を使った条件分岐について学んでいきます。 条件分岐を使うことで、特定の条件を満たすかどうかで行う処理を変更できます。

― この文章は © 2023 jsprimer project クリエイティブ・コモンズ CC BY 4.0 ライセンスのもとに利用を許諾されています。

続きは JavaScript Primer > 基本文法 > 条件分岐 を参照しましょう。

ポイント

  • if文

やってみよう!

let color = "white";

if (Math.random() < 0.5) {
  color = "green";
}

document.body.style.backgroundColor = color;
document.body.textContent = `今日のラッキーカラー: ${color}`;

関数と宣言

JavaScript Primer > 基本文法 > 関数と宣言

関数とは、ある一連の手続き(文の集まり)を1つの処理としてまとめる機能です。 関数を利用することで、同じ処理を毎回書くのではなく、一度定義した関数を呼び出すことで同じ処理を実行できます。

これまで利用してきたコンソール表示をするConsole APIも関数です。 console.logは「受け取った値をコンソールへ出力する」という処理をまとめた関数です。

この章では、関数の定義方法や呼び出し方について見ていきます。

― この文章は © 2023 jsprimer project クリエイティブ・コモンズ CC BY 4.0 ライセンスのもとに利用を許諾されています。

続きは JavaScript Primer > 基本文法 > 関数と宣言 を参照しましょう。

ポイント

  • 関数の宣言方法

やってみよう!

function 円の面積(r) {
  return Math.PI * r * r;
}

const r1 = 1;
const r2 = 3;

document.body.textContent = `
半径 ${r1} m の円の面積: ${円の面積(r1)} m²
半径 ${r2} m の円の面積: ${円の面積(r2)} m²
`;

Math.PIは円周率(およそ3.14159)を表すMathオブジェクトの静的プロパティです。

ループと反復処理

JavaScript Primer > 基本文法 > ループと反復処理

この章では、while文やfor文などの基本的な反復処理と制御文について学んでいきます。

プログラミングにおいて、同じ処理を繰り返すために同じコードを繰り返し書く必要はありません。 ループやイテレータなどを使い、反復処理として同じ処理を繰り返し実行できます。

また、for文などのような構文だけではなく、配列のメソッドを利用して反復処理を行う方法もあります。 配列のメソッドを使った反復処理もよく利用されるため、合わせて見ていきます。

― この文章は © 2023 jsprimer project クリエイティブ・コモンズ CC BY 4.0 ライセンスのもとに利用を許諾されています。

続きは JavaScript Primer > 基本文法 > ループと反復処理 を参照しましょう。

ポイント

  • while文
  • for文

やってみよう!

const text = "いろはにほへと";

for (const c of text) {
  document.body.textContent += `【${c}】`;
}

非同期処理

JavaScript Primer > 基本文法 > 非同期処理:Promise/Async Function

この章ではJavaScriptの非同期処理について学んでいきます。 非同期処理はJavaScriptにおけるとても重要な概念です。 また、ブラウザやNode.jsなどのAPIには非同期処理でしか扱えないものもあるため、非同期処理を避けることはできません。 JavaScriptには非同期処理を扱うためのPromiseというビルトインオブジェクト、さらにはAsync Functionと呼ばれる構文的なサポートがあります。

この章では非同期処理とはどのようなものかという話から、非同期処理での例外処理、非同期処理の扱い方を見ていきます。

― この文章は © 2023 jsprimer project クリエイティブ・コモンズ CC BY 4.0 ライセンスのもとに利用を許諾されています。

続きは JavaScript Primer > 基本文法 > 非同期処理:Promise/Async Function を参照しましょう。

ポイント

  • 非同期処理はその処理が終わるのを待つ前に次の処理を評価すること
  • await
    • 書式: await 関数()
    • 意味: await 式は Async Function 関数() が完了するまで待つ
  • Async Function … async function 関数() { <awaitの含まれる文>; }
    • 非同期処理を行う関数
    • await 式は Async Function の中で利用できる

一定時間待機

一定時間待機するAsync Function sleep() の作り方を解説します。

setTimeout(<コールバック関数>, <ミリ秒>) 関数は指定されたミリ秒後にコールバック関数を実行するための関数です。コールバック関数とは、簡単に言うと「後で使うために渡しておく関数」です。

次のコードは「3秒後にメッセージを表示する」という処理のプログラムです。メッセージの表示処理を resolve() 関数として宣言し、その関数名をコールバック関数として書きます。

function resolve() {
  console.log("3秒!");
}

setTimeout(resolve, 3000); // 3秒 = 3,000ミリ秒

実行すると3秒後にメッセージ"3秒!"が表示されたかと思います。 これでも十分短いコードですが、今度はPromiseとawaitを使って書き換えてみます。

await new Promise((resolve) => setTimeout(resolve, 3000));
console.log("3秒!");

こうすることで上から下へと順番に実行する処理順で書けます。 これにより時間がかかるようなプログラムをもっと簡単に読みやすく書くことができます。

Note
現実世界と非同期処理

コンピューターの上ではどのようなタイミングで何を行うかプログラマーが自由に決めることができますが、現実の世界では同じ時刻でも様々な事象が常に起こっています。 私たちの日常生活は多くの非同期的なイベントで構成されていると言えます。 非同期処理の概念を理解しておくことは現実の問題をコンピューターの上で扱うのにとても役に立ちます。

関数を使用して指定されたミリ秒(ms)だけ待つように一般化してみましょう。 ここで await 式は通常の関数のなかでは利用できず、代わりにAsync Functionの中で利用できるという点に注意しましょう。

まとめるとこのようになります:

async function sleep(ms) {
  await new Promise((resolve) => setTimeout(resolve, ms));
}

使用方法:

await sleep(ミリ秒);

インターネットからのデータの取得

インターネットからデータを取得する際にも、その処理が完了するまで待つ必要があります。

書式:

let res = await fetch(取得するURL);
let data = await res.json();

最初の await 式でAPIからの応答を待ち、次に res.json() の処理の完了を待ちます。 このようにしてデータが完全に取得されるまでコードの実行が一時停止し、データが利用可能になると処理を再開します。

やってみよう!

const button = document.createElement("button");
button.textContent = "スタート";
document.body.append(button);

async function sleep(ms) {
  await new Promise(resolve => setTimeout(resolve, ms));
}

button.addEventListener("click", async function () {
  await sleep(3000); // クリックしてから3秒待つ

  document.body.append("3秒!");
});

暗黙的な型変換

JavaScript Primer > 基本文法 > 暗黙的な型変換

この章では、明示的な型変換と暗黙的な型変換について学んでいきます。

演算子」の章にて、 等価演算子(==)ではなく厳密等価演算子(===)の利用を推奨していました。 これは厳密等価演算子(===)が暗黙的な型変換をせずに、値同士を比較できるためです。

厳密等価演算子(===)では異なるデータ型を比較した場合に、その比較結果は必ずfalseとなります。 次のコードは、数値の1と文字列の"1"という異なるデータ型を比較しているので、結果はfalseとなります。

// `===`では、異なるデータ型の比較結果はfalse
console.log(1 === "1"); // => false

しかし、等価演算子(==)では異なるデータ型を比較した場合に、同じ型となるように暗黙的な型変換をしてから比較します。 次のコードでは、数値の1と文字列の"1"の比較結果がtrueとなっています。 これは、等価演算子(==)は右辺の文字列"1"を数値の1へと暗黙的な型変換をしてから、比較するためです。

// `==`では、異なるデータ型は暗黙的な型変換をしてから比較される
// 暗黙的な型変換によって 1 == 1 のように変換されてから比較される
console.log(1 == "1"); // => true

このように、暗黙的な型変換によって意図しない結果となるため、比較には厳密等価演算子(===)を使うべきです。

別の暗黙的な型変換の例として、数値と真偽値の加算を見てみましょう。 多くの言語では、数値と真偽値の加算のような異なるデータ型同士の加算はエラーとなります。 しかし、JavaScriptでは暗黙的な型変換が行われてから加算されるため、エラーなく処理されます。

次のコードでは、真偽値のtrueが数値の1へと暗黙的に変換されてから加算処理が行われます。

// 暗黙的な型変換が行われ、数値の加算として計算される
1 + true; // => 2
// 次のように暗黙的に変換されてから計算される
1 + 1; // => 2

JavaScriptでは、エラーが発生するのではなく、暗黙的な型変換が行われてしまうケースが多くあります。 暗黙的に変換が行われた場合、プログラムは例外を投げずに処理が進むため、バグの発見が難しくなります。 このように、暗黙的な型変換はできる限り避けるべき挙動です。

この章では、次のことについて学んでいきます。

  • 暗黙的な型変換とはどのようなものなのか
  • 暗黙的ではない明示的な型変換の方法
  • 明示的な変換だけでは解決しないこと

― この文章は © 2023 jsprimer project クリエイティブ・コモンズ CC BY 4.0 ライセンスのもとに利用を許諾されています。

続きは JavaScript Primer > 基本文法 > 暗黙的な型変換 を参照しましょう。

ポイント

  • 暗黙的な型変換がある
  • できるだけ === での比較や明示的な型変換をしたほうが読みやすい

文と式

JavaScript Primer > 基本文法 > 文と式

本格的に基本文法について学ぶ前に、JavaScriptというプログラミング言語がどのような要素からできているかを見ていきましょう。

― この文章は © 2023 jsprimer project クリエイティブ・コモンズ CC BY 4.0 ライセンスのもとに利用を許諾されています。

続きは JavaScript Primer > 基本文法 > 文と式 を参照しましょう。

ポイント

  • JavaScriptは文(Statement)と式(Expression)から構成される
  • 式は値を生成し、変数に代入できるもの
  • 文は処理の単位
  • 文の末尾にはセミコロン;をつける

オブジェクト

JavaScript Primer > 基本文法 > オブジェクト

オブジェクトはプロパティの集合です。プロパティとは名前(キー)と値(バリュー)が対になったものです。 プロパティのキーには文字列またはSymbolが利用でき、値には任意のデータを指定できます。 また、1つのオブジェクトは複数のプロパティを持てるため、1つのオブジェクトで多種多様な値を表現できます。

今までも登場してきた、配列や関数などもオブジェクトの一種です。 JavaScriptには、あらゆるオブジェクトの元となるObjectというビルトインオブジェクトがあります。 ビルトインオブジェクトは、実行環境にあらかじめ定義されているオブジェクトのことです。 ObjectというビルトインオブジェクトはECMAScriptの仕様で定義されているため、あらゆるJavaScriptの実行環境で利用できます。

この章では、オブジェクトの作成や扱い方、Objectというビルトインオブジェクトについて見ていきます。

― この文章は © 2023 jsprimer project クリエイティブ・コモンズ CC BY 4.0 ライセンスのもとに利用を許諾されています。

続きは JavaScript Primer > 基本文法 > オブジェクト を参照しましょう。

ポイント

  • オブジェクトはプロパティの集合
  • {}(オブジェクトリテラル)でのオブジェクトの作成や更新方法

配列

JavaScript Primer > 基本文法 > 配列

配列はJavaScriptの中でもよく使われるオブジェクトです。

配列とは値に順序をつけて格納できるオブジェクトです。 配列に格納したそれぞれの値のことを要素、それぞれの要素の位置のことをインデックスindex)と呼びます。 インデックスは先頭の要素から012のように0からはじまる連番となります。

またJavaScriptにおける配列は可変長です。 そのため配列を作成後に配列へ要素を追加したり、配列から要素を削除できます。

この章では、配列の基本的な操作と配列を扱う場合においてのパターンについて学びます。

― この文章は © 2023 jsprimer project クリエイティブ・コモンズ CC BY 4.0 ライセンスのもとに利用を許諾されています。

続きは JavaScript Primer > 基本文法 > 配列 を参照しましょう。

ポイント

  • 配列は値に順序をつけて格納できるオブジェクト
  • [](配列リテラル)での配列の作成や更新方法

やってみよう!

function drawFortune() {
  const fortunes = ["大吉", "中吉", "吉", "小吉", "凶", "大凶"];
  const i = Math.floor(Math.random() * fortunes.length);

  document.body.textContent = `あなたの運勢は... ${fortunes[i]}です!`;
}

drawFortune();
  • Math - JavaScript | MDN
    • Math.floor(x)x以下の最大の整数を返します。
    • Math.random()0以上1未満の疑似乱数を返します。

Webサイトを公開する

作成したWebサイトをインターネット上に公開する方法を説明します。

公開する方法

Webサイトを公開する方法にはいくつもありますが、ここでは無料で公開できる2つの方法を紹介します。

方法1: Glitchを使う (短時間)

Glitch https://glitch.com を使うと短い時間でWebサイトを公開できます (ただし無料版では限られた時間しかアクセスできないので注意しましょう)。

Webページを公開する流れ:

  1. https://glitch.com にアクセス
  2. Basic website > [Remix] を選択
  3. ファイルを編集

Webブラウザーに表示された画面の「index.html」のコードを編集することですぐにWebサイトとして公開されます。

編集画面の下の 🔍 [PREVIEW] > [Preview in a new Window] から公開したWebサイトにアクセスします。

方法2: GitHubを使う

GitHub https://github.com を使うことでより本格的にWebサイトを公開できます (このガイドもそうです)。

GitHubを使うにはアカウントの作成が必要です。まずGitHubの無料アカウントを作成しましょう。

Webページを公開する流れ:

  1. GitHubでのアカウントの作成
  2. GitHub Pagesサイトの作成

自分に合った方法でWebサイトを公開してみましょう!

GitHubでのアカウントの作成

GitHub Pagesサイトの作成

Google Apps Script (GAS) で作るWebアプリ

Webブラウザー上で動作するアプリの作り方を紹介します。地図を表示するためのサードパーティAPI、Google Apps Script、そしてWebブラウザーの位置情報APIの使い方を説明します。

地図上に位置を表示する

地図を表示するためのサードパーティAPI (Leaflet) を使用し、地図上に位置を表示します。

書式

地図:

<link rel="stylesheet" href="https://unpkg.com/leaflet/dist/leaflet.css" />
<script src="https://unpkg.com/leaflet"></script>
<script type="module">
  const map = L.map("map").setView([36, 138], 15);

  // OpenStreetMapのデータはOpen Database Licenseのもとに利用を許諾されています。
  L.tileLayer("https://tile.openstreetmap.org/{z}/{x}/{y}.png", {
    attribution: `&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors`,
  }).addTo(map);
</script>
<h1>位置情報メモ</h1>
<div id="map" style="width: 500px; height: 500px"></div>

現在地の取得:

async function getLatLng() {
  const position = await new Promise((resolve, reject) =>
    navigator.geolocation.getCurrentPosition(resolve, reject),
  );

  return [position.coords.latitude, position.coords.longitude];
}

// [<緯度>, <経度>]
const here = await getLatLng();

丸いマーカーの表示:

L.circleMarker([<緯度>, <経度>]).addTo(map);

地図の移動:

map.flyTo([<緯度>, <経度>]);

サンプルコード (全体)

<!doctype html>
<meta charset="UTF-8" />
<title>GASで作るWebアプリ - 位置情報メモ</title>
<link rel="stylesheet" href="https://unpkg.com/leaflet/dist/leaflet.css" />
<script src="https://unpkg.com/leaflet"></script>
<script type="module">
  /** 経緯度の取得 */
  async function getLatLng() {
    const position = await new Promise((resolve, reject) =>
      navigator.geolocation.getCurrentPosition(resolve, reject),
    );

    return [position.coords.latitude, position.coords.longitude];
  }

  const map = L.map("map").setView([36, 138], 15);

  // OpenStreetMapのデータはOpen Database Licenseのもとに利用を許諾されています。
  L.tileLayer("https://tile.openstreetmap.org/{z}/{x}/{y}.png", {
    attribution: `&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors`,
  }).addTo(map);

  // 現在地
  const here = await getLatLng();
  // 現在地にマーカーを表示
  L.circleMarker(here).addTo(map);
  // 現在地に移動
  map.flyTo(here);
</script>

<h1>位置情報メモ</h1>
<div id="map" style="width: 500px; height: 500px"></div>

Note
[36, 138]は日本の地理的中心、北緯36度東経138度、長野県上伊那郡かみいなぐん辰野町たつのまちの区有林。

位置情報API (Geolocation API) を使用すると、自分の位置情報をWebアプリから取得することができます。 位置情報APIの初回使用時には、位置情報の許可を求められるので[許可]を選択します。

位置情報が地図上に表示されることを確認してみましょう。

スプレッドシートの作成

Googleスプレッドシートを作成し、Google Apps Scriptのプロジェクトを作成します。

事前準備

  • Googleアカウント

スプレッドシートの作成

https://sheet.new にアクセス、または「スプレッドシートのホーム画面」を開き、+をクリックします。

参考: Google スプレッドシートの使い方 - パソコン - Google ドキュメント エディタ ヘルプ

プロジェクトの作成

[拡張機能] > [Apps Script] を選択し、Google Apps Scriptのプロジェクトを作成します。

以下のコードをコピーして貼り付け、💾 [プロジェクトを保存] します。

// 最初のシート
const [sheet] = SpreadsheetApp.getActiveSpreadsheet().getSheets();

/**
 * @example 行全体の取得
 * const res = await fetch("https://script.google.com/{SCRIPTID}/exec");
 * const rows = await res.json();
 * // [
 * //   ["2006-01-02T15:04:05.999Z",1,2],
 * //   ["2006-01-02T15:04:06.000Z",3,4],
 * //   ...
 * // ]
 */
function doGet() {
  const rows = sheet.getDataRange().getValues().slice(1);
  return ContentService.createTextOutput(JSON.stringify(rows)).setMimeType(
    ContentService.MimeType.JSON,
  );
}

/**
 * @example 行の挿入
 * const row = [5,6];
 * await fetch("https://script.google.com/{SCRIPTID}/exec", { method: "POST", body: JSON.stringify(row) })
 */
function doPost(e) {
  const row = JSON.parse(e.postData.contents);
  sheet.appendRow([new Date(), ...row]);
  return doGet();
}

プロジェクトを保存できたら、そのプロジェクトを利用可能にデプロイします。

プロジェクトのデプロイ

プロジェクトを新しくデプロイするには [デプロイ] > [新しいデプロイ] から行います。

[種類の選択] ⚙ > [ウェブアプリ] を選択します。

[アクセスできるユーザー] > [全員] を選択し、[デプロイ] を選択します。

Googleアカウントへのアクセス許可を求められるのでアカウントを選択し、[Allow]許可 をクリックします

WebアプリのURLが表示されればデプロイ完了です。

データの送信にはこのWebアプリのURL (https://script.google.com/macros/s/AKf...) を使用します。

このURLはコピーしておきましょう。

使用方法

データの取得:

// ここはWebアプリのURLに書き換えます
const endpoint = "https://script.google.com/{SCRIPTID}/exec";
const res = await fetch(endpoint);
const rows = await res.json();

データの送信:

// ここはWebアプリのURLに書き換えます
const endpoint = "https://script.google.com/{SCRIPTID}/exec";
const row = [...<送信する内容>...];

await fetch(endpoint, { method: "POST", body: JSON.stringify(row) });

WebアプリのURLと送信する内容の部分は適宜変更して使用します。

送信してみよう!

サンプルコード:

const row = [42];
await fetch(endpoint, { method: "POST", body: JSON.stringify(row) });

endpoint =

レスポンス:

null

データを送信する

フォームからデータを送信してみましょう。

書式

HTMLとJavaScriptでコメント入力欄を作ります。

HTML:

<form>
  <input name="comment" placeholder="コメント" required />
  <button type="submit">送信</button>
</form>

JavaScript:

// ここはWebアプリのURLに書き換えます
const endpoint = "https://script.google.com/{SCRIPTID}/exec";

const form = document.querySelector("form");

form.addEventListener("submit", async function submit(e) {
  e.preventDefault();
  document.body.style.cursor = "wait";

  const formData = new FormData(form);
  const comment = formData.get("comment");
  const row = [comment];

  await fetch(endpoint, { method: "POST", body: JSON.stringify(row) });

  location.reload();
});

サンプルコード (全体)

<!doctype html>
<meta charset="UTF-8" />
<title>GASで作るWebアプリ - 位置情報メモ</title>
<meta name="viewport" content="width=device-width" />
<link rel="stylesheet" href="https://unpkg.com/leaflet/dist/leaflet.css" />
<script src="https://unpkg.com/leaflet"></script>
<script type="module">
  /** 経緯度の取得 */
  async function getLatLng() {
    const position = await new Promise((resolve, reject) =>
      navigator.geolocation.getCurrentPosition(resolve, reject),
    );

    return [position.coords.latitude, position.coords.longitude];
  }

  const map = L.map("map").setView([36, 138], 15);

  // OpenStreetMapのデータはOpen Database Licenseのもとに利用を許諾されています。
  L.tileLayer("https://tile.openstreetmap.org/{z}/{x}/{y}.png", {
    attribution: `&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors`,
  }).addTo(map);

  // 現在地
  const here = await getLatLng();
  // 現在地にマーカーを表示
  L.circleMarker(here).addTo(map);
  // 現在地に移動
  map.flyTo(here);

  // ここはWebアプリのURLに書き換えます
  const endpoint = "https://script.google.com/{SCRIPTID}/exec";

  const form = document.querySelector("form");

  form.addEventListener("submit", async function submit(e) {
    e.preventDefault();
    document.body.style.cursor = "wait";

    const formData = new FormData(form);
    const comment = formData.get("comment");
    const row = [comment];

    await fetch(endpoint, { method: "POST", body: JSON.stringify(row) });

    location.reload();
  });
</script>

<h1>位置情報メモ</h1>
<div id="map" style="width: 500px; height: 500px"></div>
<form>
  <input name="comment" placeholder="コメント" required />
  <button type="submit">送信</button>
</form>

コメントを入力し、[送信] を選択します。

スプレッドシートにコメントのデータが記録されていることを確認してみましょう。

位置情報を送信する

ここまで説明に沿ってやってきていたら comment の後ろに現在地を書き加えれば現在地の緯度・経度を送信できます。

const row = [comment];

const row = [comment, here[0], here[1]];

このように書き加えればOKです。

書式

// コメント, 緯度, 経度
const row = [comment, here[0], here[1]];

サンプルコード (全体)

<!doctype html>
<meta charset="UTF-8" />
<title>GASで作るWebアプリ - 位置情報メモ</title>
<meta name="viewport" content="width=device-width" />
<link rel="stylesheet" href="https://unpkg.com/leaflet/dist/leaflet.css" />
<script src="https://unpkg.com/leaflet"></script>
<script type="module">
  /** 経緯度の取得 */
  async function getLatLng() {
    const position = await new Promise((resolve, reject) =>
      navigator.geolocation.getCurrentPosition(resolve, reject),
    );

    return [position.coords.latitude, position.coords.longitude];
  }

  const map = L.map("map").setView([36, 138], 15);

  // OpenStreetMapのデータはOpen Database Licenseのもとに利用を許諾されています。
  L.tileLayer("https://tile.openstreetmap.org/{z}/{x}/{y}.png", {
    attribution: `&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors`,
  }).addTo(map);

  // 現在地
  const here = await getLatLng();
  // 現在地にマーカーを表示
  L.circleMarker(here).addTo(map);
  // 現在地に移動
  map.flyTo(here);

  // ここはWebアプリのURLに書き換えます
  const endpoint = "https://script.google.com/{SCRIPTID}/exec";

  const form = document.querySelector("form");

  form.addEventListener("submit", async function submit(e) {
    e.preventDefault();
    document.body.style.cursor = "wait";

    const formData = new FormData(form);
    const comment = formData.get("comment");
    const row = [comment, here[0], here[1]];

    await fetch(endpoint, { method: "POST", body: JSON.stringify(row) });

    location.reload();
  });
</script>

<h1>位置情報メモ</h1>
<div id="map" style="width: 500px; height: 500px"></div>
<form>
  <input name="comment" placeholder="コメント" required />
  <button type="submit">送信</button>
</form>

スプレッドシートに位置情報が記録されていることを確認してみましょう。

データを取得する

最後にスプレッドシートのデータを地図上に表示してみましょう。

書式

データの取得:

const res = await fetch(endpoint);
const rows = await res.json();

// 日付と時刻, コメント, 緯度, 経度
for (const [timestamp, comment, lat, lng] of rows) {
  // 日付と時刻
  const date = new Date(timestamp).toLocaleString();
  // …
}

マーカーの追加:

const popup = document.createElement("span");
popup.textContent = <表示する内容>;
L.marker([<緯度>, <経度>]).addTo(map).bindPopup(popup);

サンプルコード (全体)

<!doctype html>
<meta charset="UTF-8" />
<title>GASで作るWebアプリ - 位置情報メモ</title>
<meta name="viewport" content="width=device-width" />
<link rel="stylesheet" href="https://unpkg.com/leaflet/dist/leaflet.css" />
<script src="https://unpkg.com/leaflet"></script>
<script type="module">
  /** 経緯度の取得 */
  async function getLatLng() {
    const position = await new Promise((resolve, reject) =>
      navigator.geolocation.getCurrentPosition(resolve, reject),
    );

    return [position.coords.latitude, position.coords.longitude];
  }

  const map = L.map("map").setView([36, 138], 15);

  // OpenStreetMapのデータはOpen Database Licenseのもとに利用を許諾されています。
  L.tileLayer("https://tile.openstreetmap.org/{z}/{x}/{y}.png", {
    attribution: `&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors`,
  }).addTo(map);

  // 現在地
  const here = await getLatLng();
  // 現在地にマーカーを表示
  L.circleMarker(here).addTo(map);
  // 現座地に移動
  map.flyTo(here);

  // ここはWebアプリのURLに書き換えます
  const endpoint = "https://script.google.com/{SCRIPTID}/exec";

  const res = await fetch(endpoint);
  const rows = await res.json();

  for (const [timestamp, comment, lat, lng] of rows) {
    const date = new Date(timestamp).toLocaleString();
    const popup = document.createElement("span");
    popup.textContent = `${date}: ${comment}`;
    L.marker([lat, lng]).addTo(map).bindPopup(popup);
  }

  const form = document.querySelector("form");

  form.addEventListener("submit", async function submit(e) {
    e.preventDefault();
    document.body.style.cursor = "wait";

    const formData = new FormData(form);
    const comment = formData.get("comment");
    const row = [comment, here[0], here[1]];

    await fetch(endpoint, { method: "POST", body: JSON.stringify(row) });

    location.reload();
  });
</script>

<h1>位置情報メモ</h1>
<div id="map" style="width: 500px; height: 500px"></div>
<form>
  <input name="comment" placeholder="コメント" required />
  <button type="submit">送信</button>
</form>

やってみよう!

  • より魅力的にしていくにはどうすればよいか考えてみましょう
    • 例: CSSを使ってきれいな見た目にする?
    • 例: コードを整理する?
  • 思いついたら「とりあえずやってみる」

参考文献

Raspberry Piで温度センサーのデータの送信

Google Apps Scriptを利用してRaspberry Piからスプレッドシートにデータを送信する方法を説明します。

スプレッドシートの作成

Googleスプレッドシートを作成し、Google Apps Scriptのプロジェクトを作成します。

事前準備

  • Googleアカウント

スプレッドシートの作成

https://sheet.new にアクセス、または「スプレッドシートのホーム画面」を開き、+をクリックします。

参考: Google スプレッドシートの使い方 - パソコン - Google ドキュメント エディタ ヘルプ

プロジェクトの作成

[拡張機能] > [Apps Script] を選択し、Google Apps Scriptのプロジェクトを作成します。

以下のコードをコピーして貼り付け、💾 [プロジェクトを保存] します。

// 最初のシート
const [sheet] = SpreadsheetApp.getActiveSpreadsheet().getSheets();

/**
 * @example 行全体の取得
 * const res = await fetch("https://script.google.com/{SCRIPTID}/exec");
 * const rows = await res.json();
 * // [
 * //   ["2006-01-02T15:04:05.999Z",1,2],
 * //   ["2006-01-02T15:04:06.000Z",3,4],
 * //   ...
 * // ]
 */
function doGet() {
  const rows = sheet.getDataRange().getValues().slice(1);
  return ContentService.createTextOutput(JSON.stringify(rows)).setMimeType(
    ContentService.MimeType.JSON,
  );
}

/**
 * @example 行の挿入
 * const row = [5,6];
 * await fetch("https://script.google.com/{SCRIPTID}/exec", { method: "POST", body: JSON.stringify(row) })
 */
function doPost(e) {
  const row = JSON.parse(e.postData.contents);
  sheet.appendRow([new Date(), ...row]);
  return doGet();
}

プロジェクトを保存できたら、そのプロジェクトを利用可能にデプロイします。

プロジェクトのデプロイ

プロジェクトを新しくデプロイするには [デプロイ] > [新しいデプロイ] から行います。

[種類の選択] ⚙ > [ウェブアプリ] を選択します。

[アクセスできるユーザー] > [全員] を選択し、[デプロイ] を選択します。

Googleアカウントへのアクセス許可を求められるのでアカウントを選択し、[Allow]許可 をクリックします

WebアプリのURLが表示されればデプロイ完了です。

データの送信にはこのWebアプリのURL (https://script.google.com/macros/s/AKf...) を使用します。

このURLはコピーしておきましょう。

使用方法

データの取得:

// ここはWebアプリのURLに書き換えます
const endpoint = "https://script.google.com/{SCRIPTID}/exec";
const res = await fetch(endpoint);
const rows = await res.json();

データの送信:

// ここはWebアプリのURLに書き換えます
const endpoint = "https://script.google.com/{SCRIPTID}/exec";
const row = [...<送信する内容>...];

await fetch(endpoint, { method: "POST", body: JSON.stringify(row) });

WebアプリのURLと送信する内容の部分は適宜変更して使用します。

送信してみよう!

サンプルコード:

const row = [42];
await fetch(endpoint, { method: "POST", body: JSON.stringify(row) });

endpoint =

レスポンス:

null

温度センサーのデータの送信

それではRaspberry Piからスプレッドシートにデータを送信してみましょう。

温度センサー SHT30 を利用して温度のデータを送信します。

事前準備

  • Raspberry Pi
  • SHT30 (温度・湿度センサ)
  • 配線用のワイヤー

サンプルコード

次のようなNode.jsのコードを実行することでデータを送信します:

// ここはWebアプリのURLに書き換えます
const endpoint = "https://script.google.com/{SCRIPTID}/exec";

import { requestI2CAccess } from "node-web-i2c";
import SHT30 from "@chirimen/sht30";

const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));

const i2cAccess = await requestI2CAccess();
const port = i2cAccess.ports.get(1);
const sht30 = new SHT30(port, 0x44);
await sht30.init();

while (true) {
  const { humidity, temperature } = await sht30.readData();
  const row = [temperature];

  await fetch(endpoint, { method: "POST", body: JSON.stringify(row) });

  const message = `現在の温度は${temperature.toFixed(2)}度です`;

  console.log(endpoint, message);

  // 10秒待機
  await sleep(10000); // ms
}

スプレッドシートに温度センサーのデータが記録されていることを確認してみましょう。

グラフの作成

Googleスプレッドシートでグラフを作成します。

  1. グラフの列を選択します
  2. [挿入] > [グラフ] を選択します

グラフのタイトル

グラフの見た目を変更する方法をいくつか紹介します。

  1. 変更するグラフをダブルクリックします
  2. 右側の [カスタマイズ] を選択します
  3. [グラフと軸のタイトル] を選択します
  4. [グラフのタイトル] > タイトルテキストを入力します

縦軸の範囲の変更

縦軸の表示範囲は [縦軸] > [最小値]/[最大値] を入力します。

目盛り

目盛りの追加は [グリッドラインと目盛] > [主目盛り]/[補助目盛り] を選択します。

表示形式

  1. グラフの列を選択します
  2. [表示形式] メニューから表示形式を選択します

参考文献

Raspberry Piからスマートフォンにデータを送信する

ntfy.shを利用してRaspberry Piからスマートフォンにデータを送信する方法を説明します。

ntfy.shは、ユーザーに通知を送信するためのシンプルなサービスです。このサービスは特定のイベントや条件が発生したときに通知を送るために利用できます。

制約事項

(無料枠) 1日あたりのメッセージの上限は250件です。 10分あたり1件程度の通知を目安にしましょう。

その他にもAPIにはいくつかの制限があります。注意して利用しましょう。

制限説明
メッセージの長さ各メッセージの長さは最大 4,096 バイトです。長いメッセージは添付ファイルとして扱われます。
リクエストデフォルトでは、サーバーは訪問者あたり一度に 60 件のリクエストを許可し、その後 5 秒に 1 件の割合で許可されたリクエスト バケットを補充するように設定されています。
1 日あたりのメッセージデフォルトでは、メッセージ数はリクエスト制限によって制御されます。これはオーバーライドできます。 ntfy.sh では、1 日あたりのメッセージ制限は 250 です。
メールデフォルトでは、サーバーは訪問者ごとに一度に 16 通の電子メールを送信できるように設定されており、許可された電子メール バケットは 1 時間に 1 通の割合で補充されます。 ntfy.sh では、1 日あたりの制限は 5 です。
電話通話デフォルトでは、通話制限のある層を持つユーザーを除き、サーバーは電話通話を許可しません。
サブスクリプション制限デフォルトでは、サーバーは各訪問者がサーバーへの 30 接続を開いたままにすることを許可します。
添付ファイルのサイズ制限デフォルトでは、サーバーは添付ファイルのサイズが最大 15 MB、訪問者あたり合計で最大 100 MB、訪問者全体で最大 5 GB まで許可します。 ntfy.sh では、添付ファイルのサイズ制限は 2 MB で、訪問者あたりの合計は 20 MB です。
添付ファイルの有効期限デフォルトでは、サーバーは 3 時間後に添付ファイルを削除するため、訪問者の添付ファイルの合計制限からスペースが解放されます。
添付ファイルの帯域幅デフォルトでは、サーバーは 24 時間以内に訪問者ごとに 500 MB の添付ファイルの GET/PUT/POST トラフィックを許可します。それを超えるトラフィックは拒否されます。 ntfy.sh では、1 日の帯域幅制限は 200 MB です。
トピックの総数デフォルトでは、サーバーは 15,000 のトピックを許可するように構成されています。ただし、ntfy.sh サーバーにはより高い制限があります。

https://docs.ntfy.sh/publish/#limitations より

トピックの作成

ntfy.shを利用するには、まずトピックを作成します。

新しいトピックを作成してみましょう:

トピックにアクセスし[購読]することで通知を受け取ることができるようになります。 このときのURLは忘れないようにメモしておきます。

使用方法

メッセージの送信:

// ここはntfy.shのURLに書き換えます
const endpoint = "https://ntfy.sh/mytopic";
const message = `<メッセージ本文>`;
const res = await fetch(endpoint, { method: "POST", body: message });

送信してみよう!

サンプルコード:

const message = `現在の時刻は ${new Date().toTimeString()} です`;
await fetch(endpoint, { method: "POST", body: message });

endpoint =

レスポンス:

null

温度センサーのデータの送信

それではRaspberry Piからスマートフォンにデータを送信してみましょう。

温度センサー SHT30 を利用して温度のデータを送信します。

事前準備

  • Raspberry Pi
  • SHT30 (温度・湿度センサ)
  • 配線用のワイヤー

配線図

書式

// ここはntfy.shのURLに書き換えます
const endpoint = <ntfy.shのURL>;

await fetch(endpoint, { method: "POST", body: <送信する内容> });

ntfy.shのURLと送信する内容の部分を書き換えて使用します。

スマートフォンに温度センサーのデータが送信されていることを確認してみましょう。

サンプルコード

次のようなNode.jsのコードを実行することでデータを送信します:

// ここはntfy.shのURLに書き換えます
const endpoint = "https://ntfy.sh/536804b7-65aa-403f-97f6-7bd945e83491";

import { requestI2CAccess } from "node-web-i2c";
import SHT30 from "@chirimen/sht30";

const i2cAccess = await requestI2CAccess();
const port = i2cAccess.ports.get(1);
const sht30 = new SHT30(port, 0x44);
await sht30.init();

const { humidity, temperature } = await sht30.readData();
const message = `現在の温度は${temperature.toFixed(2)}度です`;

await fetch(endpoint, { method: "POST", body: message });

console.log(endpoint, message);

制約事項

(無料枠) 1日あたりのメッセージの上限は250件です。 10分あたり1件程度の通知を目安にしましょう。

参考: https://docs.ntfy.sh/publish/#limitations より

質問・提案・問題の報告

もし気になることなどあれば、Cosense または GitHub Issues からお気軽にお寄せください。

Scrapbox

  • 利用にはGoogleアカウントが必要です
  • 詳しくはCosenseの使い方をご参照ください

GitHub

  • 利用にはGitHubアカウントが必要です