Zenn
🍔

JavaScriptの基本的なDOM操作とイベント処理を理解しよう - ハンバーガーメニューとスムーズスクロールの実装を通して

2025/02/20に公開

こんにちは!この記事では、JavaScriptにおけるDOM操作とイベント処理について、実践的な例を通して学んでいきます。

はじめに

記事の目的

この記事では、以下の2つの機能を実装しながら、JavaScriptの基本的なDOM操作とイベント処理について学びます:

  1. ハンバーガーメニュー
  2. スムーズスクロール

これらの機能は多くのWebサイトで使用されており、実装を通してJavaScriptの重要な概念を理解することができます。

対象読者

  • HTML/CSSの基本的な知識がある方
  • JavaScriptを学び始めた方
  • DOM操作とイベント処理の基礎を学びたい方

完成イメージ

以下のような機能を持つWebページを作成します:

  • 固定ヘッダーとハンバーガーメニュー
  • メニュークリックでスムーズスクロール
  • レスポンシブ対応

1. DOMとは何か

DOMの基本概念

DOM(Document Object Model)は、HTMLドキュメントをツリー構造で表現したものです。JavaScriptを使って、このツリー構造の要素を操作することができます。

よく使うDOM操作メソッド

主なDOM操作メソッドには以下のようなものがあります:

// 要素の取得
document.querySelector('.class-name')    // 最初の要素を取得
document.querySelectorAll('.class-name') // 該当する全ての要素を取得

// クラスの操作
element.classList.add('class-name')    // クラスを追加
element.classList.remove('class-name') // クラスを削除
element.classList.toggle('class-name') // クラスの追加/削除を切り替え

実際のHTML構造との関係

以下のようなHTML構造があった場合:

<header class="header">
  <nav class="nav">
    <button class="hamburger">Menu</button>
  </nav>
</header>

JavaScriptでは以下のように要素を取得できます:

const header = document.querySelector('.header');
const nav = document.querySelector('.nav');
const hamburger = document.querySelector('.hamburger');

2. イベント処理の基礎

イベントとは

イベントとは、ユーザーの操作(クリックやスクロールなど)や、ページの読み込みなどのブラウザの動作を検知する仕組みです。

イベントリスナーの基本

イベントリスナーは、特定のイベントが発生したときに実行される関数を設定する仕組みです:

element.addEventListener('イベント名', 実行する関数);

// 例
button.addEventListener('click', () => {
  console.log('ボタンがクリックされました');
});

よく使うイベントタイプ

  • click: 要素がクリックされたとき
  • scroll: ページがスクロールされたとき
  • load: ページの読み込みが完了したとき
  • resize: ウィンドウのサイズが変更されたとき

3. ハンバーガーメニューの実装

3-1. HTML/CSSの準備

まず、必要なHTML構造を作成します:

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>DOM操作とイベント処理の学習</title>
    <link rel="stylesheet" href="styles.css">
</head>
<body>
    <header class="header">
        <h1>Company Name</h1>
        <nav class="nav">
            <button class="hamburger" aria-label="メニュー">
                <span></span>
                <span></span>
                <span></span>
            </button>
            <ul class="menu">
                <li><a href="#about">About</a></li>
                <li><a href="#service">Service</a></li>
                <li><a href="#contact">Contact</a></li>
            </ul>
        </nav>
    </header>

    <main>
        <section id="about" class="section">
            <h2>About</h2>
            <p>会社概要のセクションです。</p>
        </section>
        
        <section id="service" class="section">
            <h2>Service</h2>
            <p>サービス内容のセクションです。</p>
        </section>
        
        <section id="contact" class="section">
            <h2>Contact</h2>
            <p>お問い合わせのセクションです。</p>
        </section>
    </main>

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

次に、CSSでスタイルを設定します:

/* リセットCSS */
* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}

/* ヘッダー */
.header {
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    padding: 1rem;
    background-color: #333;
    color: #fff;
    display: flex;
    justify-content: space-between;
    align-items: center;
    z-index: 1000;
}

/* ナビゲーション */
.nav {
    position: relative;
    z-index: 1001;
}

/* ハンバーガーメニュー */
.hamburger {
    display: none;
    border: none;
    background: none;
    cursor: pointer;
    padding: 0.5rem;
    z-index: 1100;
}

.hamburger span {
    display: block;
    width: 25px;
    height: 3px;
    background-color: #fff;
    margin: 5px 0;
    transition: transform 0.3s;
}

/* メニュー */
.menu {
    list-style: none;
    display: flex;
    gap: 2rem;
}

.menu a {
    color: #fff;
    text-decoration: none;
}

/* メインコンテンツ */
.section {
    min-height: 100vh;
    padding: 6rem 2rem 2rem;
}

#about {
    background-color: #f4f4f4;
}

#service {
    background-color: #fff;
}

#contact {
    background-color: #f4f4f4;
}

/* レスポンシブ対応 */
@media (max-width: 768px) {
    .hamburger {
        display: block;
        position: fixed;
        top: 1rem;
        right: 1rem;
    }

    .menu {
        position: fixed;
        top: 0;
        right: -100%;
        width: 300px;
        height: 100vh;
        background-color: #f4f4f4;
        flex-direction: column;
        padding: 6rem 2rem;
        transition: right 0.3s;
        z-index: 1000;
    }

    .menu.active {
        right: 0;
    }

    .menu a {
        color: #333;
    }

    /* ハンバーガーメニューのアニメーション */
    .hamburger.active span:nth-child(1) {
        transform: translateY(8px) rotate(45deg);
        background-color: #333;
    }

    .hamburger.active span:nth-child(2) {
        opacity: 0;
    }

    .hamburger.active span:nth-child(3) {
        transform: translateY(-8px) rotate(-45deg);
        background-color: #333;
    }
}

3-2. クリックイベントの設定

ハンバーガーメニューのクリックイベントを実装します:

// DOM要素の取得
const hamburger = document.querySelector('.hamburger');
const menu = document.querySelector('.menu');

// クリックイベントの設定
hamburger.addEventListener('click', () => {
    // ハンバーガーメニューとメニューにactiveクラスを追加/削除
    hamburger.classList.toggle('active');
    menu.classList.toggle('active');
});

このコードにより、ハンバーガーメニューをクリックすると、メニューが表示/非表示を切り替えるようになります。

3-3. クラスの追加/削除による表示制御

classList.toggle()メソッドは、要素のクラスの有無を切り替えます:

  • クラスが存在しない場合は追加
  • クラスが存在する場合は削除

これにより、CSSで定義した.activeクラスのスタイルが適用/解除され、メニューの表示が制御されます。

4. スムーズスクロールの実装

4-1. クリックイベントの設定

メニューリンクのクリックイベントを実装します:

// メニューリンクの取得
const menuLinks = document.querySelectorAll('.menu a');

// 各リンクにクリックイベントを設定
menuLinks.forEach(link => {
    link.addEventListener('click', (e) => {
        // デフォルトの遷移を防止
        e.preventDefault();

        // メニューを閉じる
        hamburger.classList.remove('active');
        menu.classList.remove('active');

        // スクロール処理
        const targetId = link.getAttribute('href');
        const targetElement = document.querySelector(targetId);
        
        targetElement.scrollIntoView({
            behavior: 'smooth'
        });
    });
});

4-2. スクロール処理の実装

scrollIntoView()メソッドは、指定した要素が見えるように画面をスクロールします。{ behavior: 'smooth' }オプションにより、スムーズなスクロールアニメーションが実現されます。

5. よくあるエラーと対処法

  • 「xxx is not defined」エラー
    原因: DOM要素が読み込まれる前にJavaScriptが実行されている
    解決策: DOMContentLoaded イベントを使うか、スクリプトをbody終了タグの直前に配置する

  • イベントリスナーが動作しない
    原因: 要素が正しく取得できていない、またはイベントの伝播が妨げられている
    解決策: console.logで要素が取得できているか確認、イベントリスナーの設定場所を見直す

  • スタイルが適用されない
    原因: CSS優先順位(詳細度)の問題、またはセレクタの誤り
    解決策: ブラウザの開発者ツールでCSSを確認、!importantの使用(あくまで一時的な対応として)

まとめ

学んだこと

  1. DOMの基本概念と操作方法
  2. イベントリスナーの使い方
  3. クラスの追加/削除による要素の制御
  4. スムーズスクロールの実装方法

発展的な実装のヒント

  • スクロール位置の微調整(ヘッダーの高さを考慮)
  • メニューを開いているときの背景固定
  • スクロールに応じたヘッダーの表示/非表示
  • アニメーションの追加

参考リンク

以上で、基本的なDOM操作とイベント処理の解説は終わりです。この記事で学んだ内容を基に、さらに発展的な実装にチャレンジしてみてください!

Discussion

ログインするとコメントできます