HTML/CSS/JSを組み合わせて作れる簡単なミニプロジェクト5選

HTML/CSS/JSを組み合わせて作れる簡単なミニプロジェクト5選

HTML/CSS/JSを組み合わせて作れる簡単なミニプロジェクト5選

HTML/CSS/JavaScript を組み合わせたミニプロジェクトは、基礎から実践的なスキルを楽しく学ぶのに最適です。ここでは、初心者でも短時間で完成できる5つのサンプルを紹介します。

各例には HTML 構造、CSS 例、JavaScript 例を含め、セキュリティやアクセシビリティへの配慮、レスポンシブ対応にも触れています。

目次

プロジェクト1: カウンターアプリ

0

ボタンをクリックして数値を増減するシンプルなアプリです。textContent は文字列なので、parseInt() で数値に変換し、数値以外のときは 0 として扱います。

HTML 構造例

<div id="counter">
  <button id="decr">-</button>
  <span id="count">0</span>
  <button id="incr">+</button>
</div>

JavaScript 例

const countEl = document.getElementById('count');
document.getElementById('incr').addEventListener('click', () => {
  let count = parseInt(countEl.textContent, 10) || 0;
  countEl.textContent = count + 1;
});
document.getElementById('decr').addEventListener('click', () => {
  let count = parseInt(countEl.textContent, 10) || 0;
  countEl.textContent = count - 1;
});

プロジェクト2: TODOリスト

    タスクを追加・削除し、localStorage に保存すると、ページを再読み込みしても内容が残ります。入力が空のときには追加しないバリデーションを加えています。

    HTML 構造例

    <form id="todo-form">
      <input type="text" id="todo-input" placeholder="タスクを入力">
      <button type="submit">追加</button>
    </form>
    <ul id="todo-list"></ul>

    JavaScript 例(バリデーション+localStorage)

    const form  = document.getElementById('todo-form');
    const input = document.getElementById('todo-input');
    const list  = document.getElementById('todo-list');
    let todos    = JSON.parse(localStorage.getItem('todos') || '[]');
    
    function saveTodos() {
      localStorage.setItem('todos', JSON.stringify(todos));
    }
    
    function renderTodos() {
      list.innerHTML = '';
      todos.forEach((text, i) => {
        const li  = document.createElement('li');
        const btn = document.createElement('button');
        li.textContent = text;
        btn.textContent = '削除';
        btn.addEventListener('click', () => {
          todos.splice(i, 1);
          saveTodos();
          renderTodos();
        });
        li.appendChild(btn);
        list.appendChild(li);
      });
    }
    
    form.addEventListener('submit', e => {
      e.preventDefault();
      const text = input.value.trim();
      if (!text) return;  // 空文字を防止
      todos.push(text);
      saveTodos();
      renderTodos();
      input.value = '';
    });
    
    // 初期表示
    renderTodos();

    プロジェクト3: 電卓アプリ

    数式を文字列で組み立て、計算ボタンで結果を表示します。eval() はセキュリティリスクがあるため学習用途のみに限定し、実務では Function コンストラクタや専用ライブラリを検討してください。

    HTML 構造例

    <div class="calculator">
      <input type="text" id="display" aria-label="計算結果" readonly>
      <div class="keys">
        <button class="key">1</button> ... <button class="key">+</button>
        <button class="key">C</button> <button class="key">=</button>
      </div>
    </div>

    JavaScript 例

    const display = document.getElementById('display');
    document.querySelectorAll('.key').forEach(key => {
      key.addEventListener('click', () => {
        const val = key.textContent;
        if (val === '=') {
          try {
            // 学習用: evalはセキュリティリスクあり
            // Function() は渡された文字列を実行して結果を返すコンストラクタ
            display.value = Function('"use strict";return (' + display.value + ')')();
          } catch {
            alert('数式にエラーがあります');
          }
        } else if (val === 'C') {
          display.value = '';
        } else {
          display.value += val;
        }
      });
    });

    プロジェクト4: 画像スライダー

    IT戦士
    聖・社畜
    賢者・ハリー

    複数の画像を横並びにし、「次へ/前へ」ボタンで切り替えます。display: flex;transition: transform 0.5s ease; で滑らかな動きを実現し、メディアクエリでレスポンシブ対応も行います。

    HTML 構造例

    <div class="slider">
      <button id="prev">前へ</button>
      <div class="slides">
        <div class="slide">
          <img src="https://via.placeholder.com/400x200?text=1" alt="画像1">
        </div>
        <div class="slide">
          <img src="https://via.placeholder.com/400x200?text=2" alt="画像2">
        </div>
        <div class="slide">
          <img src="https://via.placeholder.com/400x200?text=3" alt="画像3">
        </div>
      </div>
      <button id="next">次へ</button>
    </div>

    CSS 例

    .slider {
      position: relative;
      overflow: hidden;
      max-width: 400px;
      margin: 1em auto;
    }
    .slides {
      display: flex;
      transition: transform 0.5s ease;
    }
    .slide {
      flex: 0 0 100%;
    }
    .slide img {
      width: 100%;
      display: block;
    }
    .slider button {
      position: absolute;
      top: 50%;
      transform: translateY(-50%);
      z-index: 10;
      background: rgba(255, 255, 255, 0.8);
      border: none;
      padding: 0.5em 1em;
      cursor: pointer;
    }
    #prev { left: 10px; }
    #next { right: 10px; }

    JavaScript 例

    (function(){
      const slider        = document.querySelector('.slider');
      const slidesWrapper = slider.querySelector('.slides');
      const slides        = slidesWrapper.children;
      const count         = slides.length;
    
      // 最初と最後をクローン
      const firstClone = slides[0].cloneNode(true);
      const lastClone  = slides[count - 1].cloneNode(true);
      slidesWrapper.appendChild(firstClone);
      slidesWrapper.insertBefore(lastClone, slidesWrapper.firstChild);
    
      let idx        = 1;  // クローン込みインデックス
      let slideWidth = slider.clientWidth;
    
      // 初期表示
      slidesWrapper.style.transition = 'none';
      slidesWrapper.style.transform  = `translateX(-${slideWidth * idx}px)`;
    
      // 繰り返し無限ループ用調整
      slidesWrapper.addEventListener('transitionend', () => {
        if (idx === 0) {
          slidesWrapper.style.transition = 'none';
          idx = count;
          slidesWrapper.style.transform  = `translateX(-${slideWidth * idx}px)`;
        }
        if (idx === count + 1) {
          slidesWrapper.style.transition = 'none';
          idx = 1;
          slidesWrapper.style.transform  = `translateX(-${slideWidth * idx}px)`;
        }
      });
    
      // ボタン制御
      document.getElementById('next').addEventListener('click', () => {
        idx++;
        slidesWrapper.style.transition = 'transform 0.5s ease';
        slidesWrapper.style.transform  = `translateX(-${slideWidth * idx}px)`;
      });
      document.getElementById('prev').addEventListener('click', () => {
        idx--;
        slidesWrapper.style.transition = 'transform 0.5s ease';
        slidesWrapper.style.transform  = `translateX(-${slideWidth * idx}px)`;
      });
    
      // レスポンシブ対応
      window.addEventListener('resize', () => {
        slideWidth = slider.clientWidth;
        slidesWrapper.style.transition = 'none';
        slidesWrapper.style.transform  = `translateX(-${slideWidth * idx}px)`;
      });
    })();

    プロジェクト5: モーダルウィンドウ

    背景を暗くして中央にポップアップを表示するモーダルです。ARIA 属性や visibilitypointer-events を利用し、表示切り替え時のアニメーションも滑らかに実現しています。

    HTML 構造例

    <button id="openModal">モーダルを開く</button>
    <div id="modal" class="modal" role="dialog" aria-modal="true" aria-labelledby="modal-title">
      <div class="modal-content">
        <h2 id="modal-title">タイトル</h2>
        <p>モーダルの内容をここに記述します。</p>
        <button id="closeModal">閉じる</button>
      </div>
    </div>

    CSS 例

    .modal {
      visibility: hidden;
      opacity: 0;
      pointer-events: none;
      position: fixed;
      top: 0; left: 0;
      width: 100%; height: 100%;
      background: rgba(0, 0, 0, 0.5);
      transition: opacity 0.3s ease, visibility 0s linear 0.3s;
    }
    .modal.active {
      visibility: visible;
      opacity: 1;
      pointer-events: auto;
      transition-delay: 0s;
    }
    .modal-content {
      background: #fff;
      margin: 10% auto;
      padding: 20px;
      width: 80%;
      max-width: 400px;
      border-radius: 8px;
    }

    JavaScript 例

    document.getElementById('openModal').addEventListener('click', () => {
      document.getElementById('modal').classList.add('active');
    });
    document.getElementById('closeModal').addEventListener('click', () => {
      document.getElementById('modal').classList.remove('active');
    });

    おわりに

    以上の5つのミニプロジェクトを通して、HTML の構造作成から CSS レイアウト、JavaScript による動的処理まで一連の流れを体験できました。

    慣れてきたらさらに機能追加やデザイン拡張、モバイル向けメディアクエリ、さらなるアクセシビリティ強化にも挑戦してみてください。

    HTMLのformタグとinput属性の使い方まとめ+バリデーション入門【初心者向け完全ガイド】

    よかったらシェアしてね!
    • URLをコピーしました!
    • URLをコピーしました!
    目次