フロントエンドエンジニア養成所

スマホ表示のハンバーガーアイコンクリック時にグローバルナビゲーションのメニューを表示させる

ヘッダのグローバルメニューは横幅が広く、スマートフォン(スマホ)画面では、横一列で表示させると窮屈な印象を与えてしまいます。

よって、スマートフォン表示では、初期表示時にはグローバルメニューを非表示にしています。

スマートフォン表示時は右上に配置したハンバーガーアイコン(三本線)のボタンをクリックすることでグローバルナビのメニューが縦に表示されるようにします。

完成系のイメージ:

Alt text

Alt text

HTMLやCSSだけでは、「ボタンをクリックしたら動く」といった、ユーザーの操作に反応するような動きを作ることはできません。

そのような動き(仕組み)を作るには、JavaScriptで処理を実装する必要があります。(JavaScriptについての解説は、こちらの記事を参照ください。)

コーディング

JavaScriptをコーディングするための準備をします。

sample-siteフォルダの配下にjsフォルダを作成し、jsフォルダにindex.jsを配置します。

sample-site
├── index.html
├── css
├──├── style.css
├──├── reset.css
├── js
├──├── index.js

index.htmlに以下の修正を加えます。

  • index.jsファイルの読み込み
  • 表示されたグローバルナビを閉じるための×ボタンを配置
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>サンプルサイト</title>
    <link rel="stylesheet" media="all" href="css/style.css" />
    <link rel="stylesheet" media="all" href="css/reset.css" />
    <script src="./js/index.js"></script> <!-- この行を追加 -->
</head>
<body>
    <header class="header">
        <div class="container">
            <div class="header-top">
                <h1 class="logo"><a href="index.html">Sample</a></h1>
                <label for="toggle" class="toggle-btn-open">
                    <span></span>
                    <span></span>
                    <span></span>
                </label>
                <div class="toggle-btn-close"></div> <!-- この行を追加 -->
                <div class="tel">TEL:00-0000-0000</div>
            </div>
            <div class="nav">
                <ul class="nav-list" role="list">
                    <li class="nav-item"><a href="#">ホーム</a></li>
                    <li class="nav-item"><a href="#">会社概要</a></li>
                    <li class="nav-item"><a href="#">事業内容</a></li>
                    <li class="nav-item"><a href="#">採用情報</a></li>
                    <li class="nav-item"><a href="#">お問い合わせ</a></li>
                </ul>
            </div>
        </div>
    </header>
    <div>
        <img src="img/mainimg.png" alt="メイン画像" class="main-img">
    </div>
    <div class="content">
        <div class="container">
            <div class="sidebar">
                <ul role="list">
                    <li><a href="#"><img src="img/banner.png" alt="バナー画像" class="banner"></a></li>
                    <li><a href="#"><img src="img/banner.png" alt="バナー画像" class="banner"></a></li>
                    <li><a href="#"><img src="img/banner.png" alt="バナー画像" class="banner"></a></li>
                </ul>
            </div>
            <div class="news">
                <h2 class="h2">新着情報</h2>
                <ul role="list">
                    <li>20XX.XX.XX 〜なニュースがありました</li>
                    <li>20XX.XX.XX 〜なニュースがありました</li>
                    <li>20XX.XX.XX 〜なニュースがありました</li>
                </ul>
            </div>
        </div>
    </div>
    <footer class="footer">
        <div class="container">
            <div class="footer-content">
                <a href="index.html" class="logo">Sample</a>
                <div class="copyright">Copyright © SAMPLE</div>
            </div>
        </div>
    </footer>
</body>
</html>

×ボタンのデザインはCSSで実装するため、CSSを以下のように修正します。

@media screen and (max-width: 768px) {
    .content .container {
        flex-direction: column;
        gap: 0;
        margin: 10px auto 20px;
    }
    .sidebar {
        order: 2;
    }
    .banner {
        width: 100%;
    }
    .news {
        order: 1;
    }
    .header-top {
        flex-direction: column;
        align-items: normal;
        position: relative;
    }
    .toggle-btn-open {
        display: block;
        cursor: pointer;
        max-width: 35px;
        width: 100%;
        position: absolute;
        top: 5px;
        right: 15px;
    }
    .toggle-btn-open span {
        display: block;
        width: 100%;
        height: 5px;
        background-color: #333;
        margin: 5px 0;
    }
    /* ここから */
    .toggle-btn-close {
        position: fixed;
        z-index: 9999;
        top: 15px;
        right: 15px;
        cursor: pointer;
        width: 30px;
        height: 30px;
        opacity: 0;
    }
    .toggle-btn-close::before, .toggle-btn-close::after {
        content: "";
        position: absolute;
        top: 50%;
        left: 50%;
        width: 5px;
        height: 30px;
        background: #C9C9C9;
    }
    .toggle-btn-close::before {
        transform: translate(-50%,-50%) rotate(45deg);
    }
    .toggle-btn-close::after {
        transform: translate(-50%,-50%) rotate(-45deg);
    }
    /* ここまで追加 */
    .tel {
        margin: 10px auto 0;
    }
    .nav {
        position: fixed;
        display: flex;
        align-items: center;
        justify-content: center;
        z-index: 999;
        top:0;
        right: -120%;
        width: 100%;
        height: 100vh;
        background:#000;
    }
    .nav-list {
        flex-direction: column;
    }
    .nav-item a {
        color: #fff;
    }
    .footer {
        padding: 25px 0 30px;
    }
    .footer .logo {
        margin-bottom: 10px;
    }
}

続いて、JavaScriptのコードの実装をしていきます。先述の通り、JavaScriptのコードはindex.jsに書いていきます。

実装する処理の詳細なイメージとしては、

  1. ボタンをクリックする
  2. グローバルナビゲーションのclass属性にactiveという名前のCSSのclassを付与(=グローバルナビゲーションを表示)
  3. グローバルナビゲーションの閉じる(×)ボタンをクリック
  4. グローバルナビゲーションのclass属性からactive のclassを削除(=グローバルナビゲーションを非表示にする)

以上になります。

まずはJavaScriptを実装しましょう。index.jsに以下のコードを記載します。

onClickToggle = () => {
    const toggleBtnClose = document.querySelector(".toggle-btn-close");
    const nav = document.querySelector(".nav");
    toggleBtnClose.classList.toggle("active");
    nav.classList.toggle("active");
}

データや値を格納するための名前のことを変数といいます。JavaScriptでは、const 変数名 = 値という形で、特定の値や要素に名前をつけて扱いやすくすることができます。

難しく感じるかもしれませんが、まずは「特定の値や要素に名前をつけられる」と覚えておけばOKです。

1行目では、HTMLファイル内のクラス名が.toggle-btn-closeの要素を取得し、それにtoggleBtnCloseという変数名をつけています。これはスマホ画面でハンバーガーアイコンを押したときに表示されるグローバルナビを「閉じるためのボタン」です。

2行目では、クラス名が.navの要素(グローバルナビ)を取得して、navという変数名をつけています。

そして3、4行目では、toggleBtnClosenavの両方にactiveクラスを「トグル(切り替え)」します。つまり、activeクラスが付いていなければ付け、付いていれば外します。

activeクラスが付いていると、グローバルナビと閉じるボタンは表示され、付いていないと非表示になります。

この関数を、htmlのtoggle-btn-open、toggle-btn-closeのclass名が付与されたボタンに付与します。

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>サンプルサイト</title>
    <link rel="stylesheet" media="all" href="css/style.css" />
    <link rel="stylesheet" media="all" href="css/reset.css" />
    <script src="./js/index.js"></script>
</head>
<body>
    <header class="header">
        <div class="container">
            <div class="header-top">
                <h1 class="logo"><a href="index.html">Sample</a></h1>
                <label for="toggle" class="toggle-btn-open" onclick="onClickToggle()"> <!-- ここを変更 -->
                    <span></span>
                    <span></span>
                    <span></span>
                </label>
                <div class="toggle-btn-close" onclick="onClickToggle()"></div> <!-- ここを変更 -->
                <div class="tel">TEL:00-0000-0000</div>
            </div>
            <div class="nav">
                <ul class="nav-list" role="list">
                    <li class="nav-item"><a href="#">ホーム</a></li>
                    <li class="nav-item"><a href="#">会社概要</a></li>
                    <li class="nav-item"><a href="#">事業内容</a></li>
                    <li class="nav-item"><a href="#">採用情報</a></li>
                    <li class="nav-item"><a href="#">お問い合わせ</a></li>
                </ul>
            </div>
        </div>
    </header>
    <div>
        <img src="img/mainimg.png" alt="メイン画像" class="main-img">
    </div>
    <div class="content">
        <div class="container">
            <div class="sidebar">
                <ul role="list">
                    <li><a href="#"><img src="img/banner.png" alt="バナー画像" class="banner"></a></li>
                    <li><a href="#"><img src="img/banner.png" alt="バナー画像" class="banner"></a></li>
                    <li><a href="#"><img src="img/banner.png" alt="バナー画像" class="banner"></a></li>
                </ul>
            </div>
            <div class="news">
                <h2 class="h2">新着情報</h2>
                <ul role="list">
                    <li>20XX.XX.XX 〜なニュースがありました</li>
                    <li>20XX.XX.XX 〜なニュースがありました</li>
                    <li>20XX.XX.XX 〜なニュースがありました</li>
                </ul>
            </div>
        </div>
    </div>
    <footer class="footer">
        <div class="container">
            <div class="footer-content">
                <a href="index.html" class="logo">Sample</a>
                <div class="copyright">Copyright © SAMPLE</div>
            </div>
        </div>
    </footer>
</body>
</html>

以上の実装により、ボタンをクリックするとグローバルナビゲーションのclass属性にactiveのclassを付与することが可能になりました。

では次は、CSSにアニメーションの処理を実装していきます。

アニメーション

実装するアニメーションは以下のようになります。

  1. 画面幅768px以下(スマホや小さい画面)で、ナビゲーションメニュー(.nav)は最初は画面の右外(画面外)に隠しておく。

  2. 画面右上にあるハンバーガーメニュー(.toggle-btn-open)を押すと、ナビゲーションメニューが右から画面内にスライドして表示される。

  3. ナビゲーションメニューが表示された状態では×ボタン(.toggle-btn-close)が表示され、このボタンを押すとメニューが右に閉じて元の状態に戻る。

CSSの実装は以下になります。

@media screen and (max-width: 768px) {
    .content .container {
        flex-direction: column;
        gap: 0;
        margin: 10px auto 20px;
    }
    .sidebar {
        order: 2;
    }
    .banner {
        width: 100%;
    }
    .news {
        order: 1;
    }
    .header-top {
        flex-direction: column;
        align-items: normal;
        position: relative;
    }
    .toggle-btn-open {
        display: block;
        cursor: pointer;
        max-width: 35px;
        width: 100%;
        position: absolute;
        top: 5px;
        right: 15px;
    }
    .toggle-btn-open span {
        display: block;
        width: 100%;
        height: 5px;
        background-color: #333;
        margin: 5px 0;
    }
    /* fadeInDelayの処理を追加 */
    @keyframes fadeInDelay {
        0% { opacity: 0; }
        100% { opacity: 1; }
    }
    .toggle-btn-close {
        position: fixed;
        z-index: 9999;
        top: 15px;
        right: 15px;
        cursor: pointer;
        width: 30px;
        height: 30px;
        opacity: 0;
        animation: fadeInDelay 1s ease 0.6s forwards; /* toggle-btn-closeのanimationにfadeInDelayを付与 */
    }
    .toggle-btn-close::before, .toggle-btn-close::after {
        content: "";
        position: absolute;
        top: 50%;
        left: 50%;
        width: 5px;
        height: 30px;
        background: #C9C9C9;
    }
    .toggle-btn-close::before {
        transform: translate(-50%,-50%) rotate(45deg);
    }
    .toggle-btn-close::after {
        transform: translate(-50%,-50%) rotate(-45deg);
    }
    /* toggle-btn-close.activeの処理を追加 */
    .toggle-btn-close.active {
        display: block;
    }
    .tel {
        margin: 10px auto 0;
    }
    .nav {
        position: fixed;
        display: flex;
        align-items: center;
        justify-content: center;
        z-index: 999;
        top:0;
        right: -120%;
        width: 100%;
        height: 100vh;
        background:#000;
        transition: all 0.6s; /* この行を追加 */
    }
    /* nav.activeの処理を追加 */
    .nav.active {
        right: 0;
    }
    .nav-list {
        flex-direction: column;
    }
    .nav-item a {
        color: #fff;
    }
    .footer {
        padding: 25px 0 30px;
    }
    .footer .logo {
        margin-bottom: 10px;
    }
}

グローバルナビ(.nav)は、right: 120%を指定されているため、画面幅768px以下(スマホや小さい画面)の初期表示時、画面の右外(画面外)に隠れています。

画面右上にあるハンバーガーメニュー(.toggle-btn-open)を押すことで、グローバルナビに.activeクラスが付与されてright: 0となり、右側からグローバルナビが出現します。

しかしこれだけでは、グローバルナビゲーションが瞬間的に画面に出現してしまうため、スライドして表示させることはできません。そこで、.navにtransition: all 0.6sを付与することで、この位置変更が0.6秒かけてスムーズに動く(アニメーションする)スライドイン・アウトの効果を生み出します。

メニューが表示された状態では、.activeクラスが付与されることで×ボタン(.toggle-btn-close)が表示されます。

×ボタンには、animationプロパティでfadeInDelayという値が設定されています。

fadeInDelayの内容は、「透明度(opacity)が0から1へ徐々に変わる」ことを示しています。

0%(アニメーション開始時点)で透明(opacity: 0)、100%(アニメーション終了時点)で完全に見える(opacity: 1)状態になります。

×ボタンのanimationはfadeInDelay 1s ease 0.6s forwards;となっています。これはアニメーション開始まで0.6秒待ち、その後1秒かけてバツボタンを透明な状態から見える状態(opacityを0から1)へ切り替えることを意味します。

×ボタンは押すと、今度はメニューが右へ閉じて元の状態に戻ります。

index.htmlを開き、サイトの表示をスマホ表示に切り替えます。(詳しい手順は、こちらの記事を参照ください。)

ハンバーガーアイコンをクリックし、グローバルメニューが表示されれば成功です。

Alt text

Alt text

このサイトを運営している人

運営者の写真

はじめまして。このサイトを運営しているsidsydです。

エンジニアをしたり、日本酒サイト「酒道」を運営したりしております。

▶ 運営者情報ページへ