HTML・CSS・JavaScript入門:インタラクティブなWebページを作る

現代のWebサイトは、連携して動く3つの技術で作られています。HTMLはコンテンツの構造を定義し、CSSは見た目とレイアウトを定義し、JavaScriptはボタンのクリックや文字入力、タブの選択など、ユーザーの操作にページを反応させます。この記事では、3つを組み合わせた小さな例を作りながら、それぞれの役割と、役割を分けることの利点を説明します。

それぞれの言語の役割

家づくりにたとえてみましょう。HTMLは骨組みと壁で、リビングやキッチン、ドアの場所を決めます。CSSは塗装や素材、家具の配置にあたり、住み心地のよい見た目を作ります。JavaScriptは電気の配線とスイッチで、スイッチを押せば明かりがつき、ドアを開けば呼び鈴が鳴ります。

この役割を分けておくと便利です。サイト全体の色を変えたいときはCSSだけを編集すればよく、構造には触れません。操作に反応する機能を追加したいときは、見た目を変えずにJavaScriptを書けます。こうするとコードは読みやすく、長期間の保守もしやすくなります。

プロジェクトの構成

`interactive-demo` というフォルダを作り、その中に3つのファイルを置きます。

3つのファイルは同じフォルダに置きます。そうすれば、HTMLからの参照を完全なアドレスで書く必要がありません。

ステップ1:HTMLの構造

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>インタラクティブ・スコアカウンター</title>
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <main class="card">
    <h1>スコアカウンター</h1>
    <p id="score-text">現在のスコア:<span id="score">0</span></p>
    <div class="buttons">
      <button id="add-btn" type="button">+1 ポイント</button>
      <button id="reset-btn" type="button">リセット</button>
    </div>
    <p id="message" aria-live="polite"></p>
  </main>
  <script src="script.js"></script>
</body>
</html>

このコードの重要な要素は3つのグループです。`id="score"` を持つスコアの数字、それぞれ独自の `id` を持つ2つのボタン、そして通知を表示する段落 `id="message"` です。`aria-live="polite"` は、内容が変わったときにスクリーンリーダーに新しいテキストを読み上げさせる指定で、画面が見えない利用者も他の人と同じ情報を受け取れます。

`<script>` を `<body>` の末尾に置くと、ページ内のすべての要素が読み込まれた後でJavaScriptが動き始めます。そのため、`id` で要素を探してもエラーになりません。

ステップ2:CSSで装飾する

:root {
  --bg: #f0f4fb;
  --card: #ffffff;
  --accent: #2255aa;
  --text: #1a1a1a;
}

body {
  margin: 0;
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--bg);
  color: var(--text);
  font-family: system-ui, sans-serif;
}

.card {
  background: var(--card);
  padding: 32px;
  border-radius: 12px;
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.1);
  text-align: center;
  width: min(90vw, 360px);
}

.buttons {
  display: flex;
  gap: 12px;
  justify-content: center;
}

button {
  padding: 10px 18px;
  border: none;
  border-radius: 8px;
  background: var(--accent);
  color: #fff;
  font-size: 16px;
  cursor: pointer;
  transition: transform 0.1s ease, opacity 0.2s ease;
}

button:hover {
  opacity: 0.9;
}

button:active {
  transform: scale(0.96);
}

#reset-btn {
  background: #8a94a8;
}

ルールを1つずつ読んでみましょう。

classとidの違いは重要です。classは同じスタイルを持つ要素をまとめるためのもので、idは特定の要素を1つだけ指し示すためのものです。

ステップ3:JavaScriptでページを動かす

const scoreEl = document.getElementById("score");
const addBtn = document.getElementById("add-btn");
const resetBtn = document.getElementById("reset-btn");
const messageEl = document.getElementById("message");

let score = 0;

function render() {
  scoreEl.textContent = score;
  if (score >= 10) {
    messageEl.textContent = "素晴らしい!10ポイントに到達しました。";
  } else {
    messageEl.textContent = "";
  }
}

addBtn.addEventListener("click", function () {
  score = score + 1;
  render();
});

resetBtn.addEventListener("click", function () {
  score = 0;
  render();
});

render();

このファイルは作業を明確な部分に分けています。

1. `document.getElementById` はHTML内の要素をidで探し、変数に保存します。最初に一度だけ探しておくと、コードが速く読みやすくなります。

2. `let score = 0` はプログラムの状態を保持します。この値が、プログラム全体が使う唯一の正しい値です。

3. 関数 `render` は `score` を読み取り、その値に合わせて画面を更新します。これは「状態から描画する」と呼ばれる考え方です。どの操作でも画面の文字を直接書き換えるのではなく、値を変えたら描画関数が表示を更新します。

4. `addEventListener("click", ...)` は、クリックイベントに関数を結び付けます。利用者がボタンをクリックするたびに、その関数が実行されます。

5. 末尾の `render()` の呼び出しにより、ページを開いた時点でスコア0が表示されます。

試してみてください。+1 を押すたびに数字が増え、10に達するとメッセージが表示され、リセットを押すと0に戻ります。

ステップ4:コードをより堅牢にする

この例は動きますが、次のような習慣を身につけるとコードがさらに強くなります。

安全確認の例は次のとおりです。

if (!scoreEl) {
  console.error("HTML に #score の要素が見つかりません");
}

`console.error` はブラウザのConsoleタブ(F12キーで開く)にメッセージを表示するので、問題の場所を素早く見つけられます。

CSSかJavaScriptか:簡単な判断基準

初心者は、ある効果をどちらの言語で実装すべきか迷うことがあります。簡単な基準があります。見た目だけの変化で、利用者の操作に依存しないならCSSを使います。たとえば、ホバー時の色変更や要素の間隔などです。動作がデータや操作に依存する場合、たとえばクリック回数を数えたり、入力された値を保存したりするならJavaScriptを使います。

たとえば、ホバー時にボタンの色を変えるのはCSSの `:hover` で実現できます。しかし、ボタンが何回押されたかを数えるにはJavaScriptが必要です。

classで見た目を切り替える

スコアが10に達したときにカードの色を変えたいとします。JavaScriptの中にスタイルを直接書くのではなく、JavaScriptからclassを追加し、見た目はCSSで定義します。

.card.success {
  background: #e6f7ec;
  border: 2px solid #2e9e5b;
}
const cardEl = document.querySelector(".card");

function render() {
  scoreEl.textContent = score;
  if (score >= 10) {
    messageEl.textContent = "素晴らしい!10ポイントに到達しました。";
    cardEl.classList.add("success");
  } else {
    messageEl.textContent = "";
    cardEl.classList.remove("success");
  }
}

この方法では役割がはっきり分かれます。JavaScriptは「今の状態は成功だ」と伝え、CSSは成功時の見た目を決めます。JavaScriptを変えずに、デザインだけを自由に変更できます。

追加の例:シンプルなタブメニュー

この例は、クリックに応じて内容を切り替えるものです。実際の多くのWebサイトで見られるパターンです。

<nav>
  <button class="tab-btn active" data-tab="home">ホーム</button>
  <button class="tab-btn" data-tab="about">自己紹介</button>
</nav>
<section class="tab-panel active" id="home">私のWebサイトへようこそ。</section>
<section class="tab-panel" id="about">私はWebの作り方を学んでいる学生です。</section>
.tab-panel { display: none; }
.tab-panel.active { display: block; }
.tab-btn.active { background: #2255aa; color: #fff; }
const buttons = document.querySelectorAll(".tab-btn");
const panels = document.querySelectorAll(".tab-panel");

buttons.forEach(function (btn) {
  btn.addEventListener("click", function () {
    const target = btn.dataset.tab;
    buttons.forEach(b => b.classList.remove("active"));
    panels.forEach(p => p.classList.remove("active"));
    btn.classList.add("active");
    document.getElementById(target).classList.add("active");
  });
});

`querySelectorAll` は、セレクタに一致するすべての要素のリストを返します。`forEach` はそのリストを順に回り、各ボタンにクリック処理を結び付けます。`btn.dataset.tab` は `data-tab` 属性の値を読み取るので、ボタンごとに別の関数を書く必要がなくなります。

JavaScriptでよくあるミス

初心者へのアドバイス

保存と実行の方法

1. `interactive-demo` という名前の新しいフォルダを作ります。

2. そのフォルダに `index.html`、`style.css`、`script.js` の3つのファイルを作り、各ステップのコードを貼り付けます。

3. ファイルはUTF-8で保存します。メモ帳なら「名前を付けて保存」で文字コードをUTF-8に設定します。そうしないと日本語が文字化けすることがあります。

4. ファイル名を確認します。Windowsではファイル名拡張子を表示する設定を先に有効にしておくと、`script.js.txt` のような誤った名前を防げます。

5. `index.html` をダブルクリックするか、ブラウザのウィンドウにドラッグします。

6. VS Codeを使う場合は Live Server を追加し、`index.html` を右クリックして「Open with Live Server」を選びます。保存するたびにページが自動で再読み込みされます。

実際に実行した結果

以下は、スコアカウンターを実際のブラウザで動かし、ボタンを順番に押して確認した結果です。テストではタイ語版のコードを使ったため、表示されるメッセージはタイ語です。

タブメニューの例も実際のブラウザで確認しました。最初のタブはホームで、「เกี่ยวกับ(自己紹介)」を押すと対応するパネルが表示され、そのボタンが強調表示されます。「หน้าแรก(ホーム)」を押すと、ホームのパネルに戻ります。テストのメッセージもタイ語でしたが、動作はどの言語でも同じです。

次のステップ

3つの言語に慣れたら、次のことにも挑戦できます。レイアウトを高度にするCSSのFlexboxとGrid、サーバーからデータを読み込む `fetch` とJSON、コードを管理するGit、そしてプロジェクトが大きくなったらReactのようなフレームワークです。

まとめ

HTMLは構造を、CSSは見た目を、JavaScriptは操作への反応を担当します。この3つの役割を分けておくと、コードは理解しやすく、変更しやすく、拡張しやすくなります。スコアカウンターやタブメニューのような小さな例から始め、少しずつ複雑さを増やしていきましょう。毎日自分でコードを書いて試すことが、読むだけの学習よりもずっと速く上達させてくれます。