冬休みにWebアプリを作ろう!JavaScript初心者向けステップガイド

冬休み2週間でWebアプリを完成させるステップガイド。新年の目標管理アプリをHTML/CSS/JavaScriptで作る方法をコード付きで解説。

2026年5月12日

冬休み2週間でWebアプリを完成させよう

冬休みに「新年の目標管理アプリ」を作ります。目標を追加・削除でき、達成した目標にチェックを入れると進捗がパーセントで表示されます。localStorage(ローカルストレージ)というブラウザの保存機能を使うので、ページを閉じても目標データが消えません。

この記事では、HTML・CSS・JavaScriptのコードを実際に書きながら、2週間で完成させるスケジュールに沿って進めます。コードはすべてコピーして動かせるので、一緒に手を動かしてみましょう。

夏休みに作れるWebアプリ10選で他のアイデアも見られます。

完成イメージと使う技術

今回作る「目標管理アプリ」の仕様を確認しましょう。

  • 入力欄に目標を書いて「追加」ボタンでリストに追加できる
  • 各目標にチェックボックスがあり、達成したらチェックを入れる
  • ×ボタンで目標を削除できる
  • 「達成率〇%」が自動計算されて表示される
  • localStorageにデータが保存され、ブラウザを閉じても消えない

使う技術は3つです。

  • HTML:入力欄・リスト・進捗バーの骨組みを作る
  • CSS:カード風のデザインと進捗バーの見た目を整える
  • JavaScript:追加・削除・達成チェック・保存のロジックを作る

1つのHTMLファイルと、CSS・JSファイルをそれぞれ1つずつ作ります。特別なソフトは不要で、ブラウザだけで動きます。

Day 1-3: HTML/CSSで見た目を作る

まずはHTMLで画面の構造を作ります。index.htmlというファイルを作り、以下のコードを書いてください。

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>2026年の目標リスト</title>
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <div class="app-container">
    <h1>2026年の目標リスト</h1>

    <!-- 目標を追加するフォーム -->
    <form id="goal-form">
      <input id="goal-input" type="text" placeholder="今年の目標を入力" required>
      <button type="submit">追加</button>
    </form>

    <!-- 進捗バー -->
    <div class="progress-wrap">
      <div id="progress-bar" class="progress-bar"></div>
    </div>
    <p id="progress-text">達成率: 0%(0/0)</p>

    <!-- 目標のリスト -->
    <ul id="goal-list"></ul>
  </div>

  <script src="script.js"></script>
</body>
</html>

ポイント解説:

  • id="goal-form"は、JavaScriptからフォームを見つけるための名札です。DOM(ドム)操作で使います。
  • required属性で、入力欄が空のまま送信できないようにしています。
  • 目標のリスト(<li>要素)は、JavaScriptから動的に追加していくので、最初は空の<ul>だけを用意します。

次にstyle.cssを作り、カード風のデザインを当てます。

* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

body {
  font-family: "Helvetica Neue", sans-serif;
  background-color: #f0f4f8;
  display: flex;
  justify-content: center;
  padding: 40px 16px;
}

.app-container {
  background: #fff;
  border-radius: 16px;
  padding: 32px;
  max-width: 480px;
  width: 100%;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
}

h1 {
  font-size: 22px;
  margin-bottom: 20px;
}

/* 入力フォーム */
#goal-form {
  display: flex;
  gap: 8px;
  margin-bottom: 20px;
}

#goal-input {
  flex: 1;
  padding: 10px 12px;
  font-size: 15px;
  border: 2px solid #ddd;
  border-radius: 8px;
}

#goal-form button {
  padding: 10px 16px;
  font-size: 15px;
  background: #007bff;
  color: #fff;
  border: none;
  border-radius: 8px;
  cursor: pointer;
}

/* 進捗バー */
.progress-wrap {
  background: #eee;
  border-radius: 999px;
  height: 12px;
  overflow: hidden;
  margin-bottom: 8px;
}

.progress-bar {
  height: 100%;
  width: 0%;
  background: #28a745;
  transition: width 0.3s;
}

#progress-text {
  font-size: 13px;
  color: #666;
  margin-bottom: 20px;
}

/* 目標リスト */
#goal-list {
  list-style: none;
}

#goal-list li {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 0;
  border-bottom: 1px solid #eee;
}

#goal-list li.done span {
  text-decoration: line-through;
  color: #aaa;
}

#goal-list li span {
  flex: 1;
}

#goal-list li button {
  background: none;
  border: none;
  color: #dc3545;
  font-size: 16px;
  cursor: pointer;
}

/* スマホ対応 */
@media (max-width: 400px) {
  #goal-form {
    flex-direction: column;
  }
}

.progress-barは今はwidth: 0%ですが、後ほどJavaScriptで達成率に応じて幅を書き換えます。ここまでできたら、ブラウザでHTMLファイルを開いて見た目を確認しておきましょう。

Day 4-7: JavaScriptで追加・削除・達成チェックを作る

script.jsというファイルを作ります。ここがアプリの「頭脳」部分です。

目標データと要素の取得

まず、目標データを入れる配列(はいれつ)と、HTML要素を取得する変数を用意します。

// 目標データを入れる配列(最初は空)
let goals = [];

// HTML要素を取得する(DOM操作)
const goalForm = document.getElementById("goal-form");
const goalInput = document.getElementById("goal-input");
const goalList = document.getElementById("goal-list");
const progressBar = document.getElementById("progress-bar");
const progressText = document.getElementById("progress-text");

目標を追加する

フォームが送信されたら、入力された文字を新しい目標として配列に追加します。

// フォーム送信時の処理
goalForm.addEventListener("submit", function (e) {
  // ページの再読み込みを止める
  e.preventDefault();

  const text = goalInput.value.trim();
  if (text === "") return;

  // 新しい目標をオブジェクトとして配列に追加
  goals.push({
    id: Date.now(), // 現在時刻を一意のIDとして使う
    text: text,
    done: false,
  });

  goalInput.value = "";
  render();
});

e.preventDefault()は「フォームの初期動作(ページの再読み込み)をしないで」という命令です。Date.now()は現在時刻をミリ秒の数値で返す関数で、目標ごとに重ならないIDとして使えます。

画面に描画する(render関数)

配列の中身をもとに、目標リストと進捗バーを画面に反映する関数を作ります。

// 目標リストと進捗を画面に反映する関数
function render() {
  // リストを一度空にする
  goalList.innerHTML = "";

  goals.forEach(function (goal) {
    const li = document.createElement("li");
    if (goal.done) li.classList.add("done");

    // チェックボックス
    const checkbox = document.createElement("input");
    checkbox.type = "checkbox";
    checkbox.checked = goal.done;
    checkbox.addEventListener("change", function () {
      toggleDone(goal.id);
    });

    // 目標テキスト
    const span = document.createElement("span");
    span.textContent = goal.text;

    // 削除ボタン
    const deleteBtn = document.createElement("button");
    deleteBtn.textContent = "×";
    deleteBtn.addEventListener("click", function () {
      deleteGoal(goal.id);
    });

    li.appendChild(checkbox);
    li.appendChild(span);
    li.appendChild(deleteBtn);
    goalList.appendChild(li);
  });

  updateProgress();
}

この関数は「配列 → 画面表示」の変換をまとめて担当します。データが変わるたびにrender()を呼び直すことで、画面が常に最新の状態になります。

達成チェックと削除の処理

チェックボックスと×ボタンから呼ばれる関数を作ります。目標のIDをもとに、配列から対象を見つけます。

// 達成/未達成を切り替える
function toggleDone(id) {
  // find()で該当するidの目標を探す
  const goal = goals.find(function (g) {
    return g.id === id;
  });
  goal.done = !goal.done;
  render();
}

// 目標を削除する
function deleteGoal(id) {
  // filter()でidが一致しないものだけ残す(=該当を除外)
  goals = goals.filter(function (g) {
    return g.id !== id;
  });
  render();
}

find()は配列から条件に合う1つの要素を探すメソッド、filter()は条件に合う要素だけを集めた新しい配列を作るメソッドです。削除では「消したいもの以外を残す」という考え方を使っています。

進捗を計算する

達成数÷全体数で達成率を計算し、進捗バーの幅とテキストを更新します。

// 進捗(達成率)を計算して表示する
function updateProgress() {
  const total = goals.length;
  const doneCount = goals.filter(function (g) {
    return g.done;
  }).length;

  // 目標が0件のときは0%にする(0÷0を避ける)
  const percent = total === 0 ? 0 : Math.round((doneCount / total) * 100);

  progressBar.style.width = percent + "%";
  progressText.textContent =
    "達成率: " + percent + "%(" + doneCount + "/" + total + ")";
}

たとえば目標が4件で2件達成していれば、doneCount / total = 2 / 4 = 0.5Math.round(0.5 * 100)で50となり「達成率: 50%(2/4)」と表示されます。目標が0件のときに0で割ってしまう(NaNになる)のを防ぐため、total === 0の分岐を入れているのがポイントです。

最後に、最初の画面表示のためにrender()を1回呼んでおきます。

// 最初の描画
render();

ここまでで、追加・達成チェック・削除・進捗表示がすべて動くようになりました。ブラウザで動作を確認してみましょう。

Day 8-10: localStorageでデータを保存する

今のままでは、ページを再読み込みすると目標データが消えてしまいます。localStorageを使って、ブラウザにデータを保存しましょう。

render()の中に保存処理を追加し、ページ読み込み時に復元する処理を足します。

// 目標データを保存する
function save() {
  // 配列を文字列(JSON)に変換して保存する
  localStorage.setItem("goals", JSON.stringify(goals));
}

// 保存されたデータを読み込む
function load() {
  const saved = localStorage.getItem("goals");
  // 保存データがあれば文字列を配列に戻す。なければ空配列
  goals = saved ? JSON.parse(saved) : [];
}

localStorageは文字列しか保存できないため、JSON.stringify()で配列を文字列に変換してから保存し、読み込むときはJSON.parse()で配列に戻します。

render()関数の最後にsave()の呼び出しを1行追加します。

function render() {
  goalList.innerHTML = "";

  goals.forEach(function (goal) {
    // (中身は変更なし。Day 4-7で作った処理のまま)
  });

  updateProgress();
  save(); // ← ここを追加:描画するたびに保存する
}

そして、ファイルの一番下にあったrender();を、読み込み処理とセットに書き換えます。

// ページ読み込み時:保存データを復元してから描画する
load();
render();

これで、目標を追加した後にページを閉じても、次に開いたときに同じ目標リストが表示されます。ブラウザの開発者ツールで「Application → Local Storage」を見ると、goalsというキーにデータが保存されているのが確認できます。

Day 11-14: テスト・改善・公開

完成が近づいたら、実際に使ってみてバグを見つけ、仕上げをしましょう。

チェックすべき動作パターン

  • 入力欄が空のまま「追加」を押すとどうなるか(requiredtrim() === ""のチェックで防げているか)
  • すべての目標を削除したとき、達成率が「0%(0/0)」に戻るか(0除算対策が効いているか)
  • チェックを入れたり外したりを繰り返して、達成率が正しく増減するか
  • ページを再読み込みしても目標が消えないか(localStorageの保存・復元)
  • スマホの画面幅で表示が崩れないか

友達や家族に使ってもらい、フィードバックをもらうのもおすすめです。「目標が多いと見づらい」「達成した項目を上に固定したい」など、実際に使った人の声から改善アイデアが見つかります。

動作が安定したら、GitHub Pagesで公開しましょう。公開すればURLを共有するだけで、誰でもアプリにアクセスできます。

カスタマイズアイデア

基本の目標管理アプリが完成したら、自分なりに機能を追加してみましょう。

1. カテゴリ分けを追加する

目標データにcategoryというプロパティ(例:"勉強"、"運動"、"趣味")を追加し、カテゴリごとに色分けして表示します。goals.push()する際にcategoryも一緒に保存する形に拡張すれば実現できます。

2. 期限設定を追加する

目標データにdeadline(期限の日付)を追加し、期限が近い目標を上に並べ替えて表示します。配列sort()メソッドを使うと並べ替えができます。

3. ダークモード切り替えを追加する

ボタンをクリックするとbody要素にdark-modeクラスをつけ外しし、CSS側で色を切り替える仕組みです。classList.toggle("dark-mode")の1行で実装できます。

独学ロードマップで次に学ぶべきことを確認しましょう。

まとめ

  • ✅ Day 1-3: HTML/CSSで入力欄・リスト・進捗バーの見た目を作った
  • ✅ Day 4-7: JSで追加・削除・達成チェック・進捗計算を実装した
  • ✅ Day 8-10: localStorageでデータの保存と復元を実装した
  • ✅ Day 11-14: 動作確認とフィードバックを経てGitHub Pagesで公開する

配列の操作(pushfindfilter)、DOM操作、イベント処理、localStorageによるデータ保存。この目標管理アプリには、Webアプリ作りに欠かせない基本テクニックが詰まっています。

冬休みの2週間で1つのアプリを完成させた経験は、次のアプリ制作でも必ず活きます。ぜひ自分だけの目標リストを育てていってください。

⚡ 完成したアプリを公開しよう!

GitHub Pagesなら無料でWebアプリを公開できます。

GitHub Pagesで公開する方法 →
目次

コースで実際に手を動かして学ぼう

レッスンではコードを書きながら基礎が身につきます

HTMLコースを始める →

同じテーマの記事

📣 この記事が役に立ったら

Xでシェア

💬 引用する場合はこちらをご利用ください:

冬休み2週間でWebアプリを完成させるステップガイド。新年の目標管理アプリをHTML/CSS/JavaScriptで作る方法をコード付きで解説。

出典: https://start-web-programming.com/blog/winter-web-app-guide/