【コピペOK】モダンなハンバーガーメニュー5選
はじめに
ハンバーガーメニューの実装は、HTMLとCSSの基礎は理解できても、スムーズなアニメーションやレスポンシブ対応となると、思うように実装できないものですよね。
特に、ポートフォリオサイトではモダンで印象的なUIを実現したくても、JavaScriptを使った実装方法や、アクセシビリティに配慮したコーディングとなると、なかなか難しいものです。
この記事では、現場で使える5種類のハンバーガーメニューを、コピー&ペーストで実装できるようにご紹介します。
パターン1:基本的なスライドインメニュー
<div class="header"> <button class="hamburger" aria-label="メニュー" aria-controls="nav-menu" aria-expanded="false"> <span class="hamburger__line"></span> <span class="hamburger__line"></span> <span class="hamburger__line"></span> </button> <nav id="nav-menu" class="nav" aria-hidden="true"> <ul class="nav__list"> <li class="nav__item"><a href="#" class="nav__link">ホーム</a></li> <li class="nav__item"><a href="#" class="nav__link">about</a></li> <li class="nav__item"><a href="#" class="nav__link">サービス</a></li> <li class="nav__item"><a href="#" class="nav__link">お問い合わせ</a></li> </ul> </nav> </div>.header { position: relative; padding: 20px; } .hamburger { position: fixed; top: 20px; right: 20px; z-index: 100; width: 48px; height: 48px; border: none; background: transparent; cursor: pointer; } .hamburger__line { position: absolute; left: 11px; width: 26px; height: 2px; background-color: #333; transition: all .4s; } .hamburger__line:nth-of-type(1) { top: 14px; } .hamburger__line:nth-of-type(2) { top: 23px; } .hamburger__line:nth-of-type(3) { top: 32px; } /* メニューオープン時 */ .hamburger.active .hamburger__line:nth-of-type(1) { transform: translateY(9px) rotate(-45deg); } .hamburger.active .hamburger__line:nth-of-type(2) { opacity: 0; } .hamburger.active .hamburger__line:nth-of-type(3) { transform: translateY(-9px) rotate(45deg); } .nav { position: fixed; top: 0; left: 0; width: 300px; height: 100vh; background-color: #fff; box-shadow: 2px 0 4px rgba(0,0,0,.1); transform: translateX(-100%); transition: transform .4s; z-index: 90; } .nav.active { transform: translateX(0); } .nav__list { margin: 0; padding: 100px 0 0; list-style: none; } .nav__item { padding: 0 20px; } .nav__link { display: block; padding: 15px 0; color: #333; text-decoration: none; border-bottom: 1px solid #eee; }// script.js document.addEventListener('DOMContentLoaded', () => { const hamburger = document.querySelector('.hamburger'); const nav = document.querySelector('.nav'); hamburger.addEventListener('click', () => { hamburger.classList.toggle('active'); nav.classList.toggle('active'); // アクセシビリティ対応 const isOpen = hamburger.classList.contains('active'); hamburger.setAttribute('aria-expanded', isOpen); nav.setAttribute('aria-hidden', !isOpen); }); // メニューの外側をクリックした時の処理 document.addEventListener('click', (e) => { if (!e.target.closest('.nav') && !e.target.closest('.hamburger') && nav.classList.contains('active')) { hamburger.classList.remove('active'); nav.classList.remove('active'); hamburger.setAttribute('aria-expanded', false); nav.setAttribute('aria-hidden', true); } }); });実装のポイント解説:- アクセシビリティへの配慮
- aria-label属性でボタンの役割を明示
- aria-expanded属性でメニューの開閉状態を通知
- aria-hidden属性でスクリーンリーダーへの表示制御
- スムーズなアニメーション
- transformとtransitionを使用した滑らかな動き
- ハンバーガーアイコンの×への変形アニメーション
- レスポンシブ対応
- vw/vh単位を使用した画面サイズ対応
- メディアクエリは不要な最小限の実装
- UX向上のための実装
- メニュー外クリックでの閉じる機能
- タッチデバイスでの操作性考慮
パターン2:オーバーレイ&円形展開メニュー
<div class="header"> <button class="hamburger-overlay" aria-label="メニュー" aria-controls="overlay-menu" aria-expanded="false"> <span class="hamburger-overlay__line"></span> <span class="hamburger-overlay__line"></span> <span class="hamburger-overlay__line"></span> </button> <nav id="overlay-menu" class="nav-overlay" aria-hidden="true"> <div class="nav-overlay__content"> <ul class="nav-overlay__list"> <li class="nav-overlay__item"><a href="#" class="nav-overlay__link">ホーム</a></li> <li class="nav-overlay__item"><a href="#" class="nav-overlay__link">サービス</a></li> <li class="nav-overlay__item"><a href="#" class="nav-overlay__link">works</a></li> <li class="nav-overlay__item"><a href="#" class="nav-overlay__link">お問い合わせ</a></li> </ul> </div> </nav> </div>/* overlay-styles.css */ .hamburger-overlay { position: fixed; top: 20px; right: 20px; z-index: 1000; width: 48px; height: 48px; border: none; background: transparent; cursor: pointer; } .hamburger-overlay__line { position: absolute; left: 11px; width: 26px; height: 2px; background-color: #333; transition: all .6s; } .hamburger-overlay__line:nth-of-type(1) { top: 14px; } .hamburger-overlay__line:nth-of-type(2) { top: 23px; } .hamburger-overlay__line:nth-of-type(3) { top: 32px; } .hamburger-overlay.active .hamburger-overlay__line { background-color: #fff; } .hamburger-overlay.active .hamburger-overlay__line:nth-of-type(1) { transform: translateY(9px) rotate(-45deg); } .hamburger-overlay.active .hamburger-overlay__line:nth-of-type(2) { opacity: 0; } .hamburger-overlay.active .hamburger-overlay__line:nth-of-type(3) { transform: translateY(-9px) rotate(45deg); } .nav-overlay { position: fixed; top: 0; left: 0; width: 100%; height: 100vh; background-color: rgba(0, 0, 0, 0.95); visibility: hidden; opacity: 0; transition: all .6s; z-index: 900; } .nav-overlay.active { visibility: visible; opacity: 1; } .nav-overlay__content { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); width: 100%; text-align: center; } .nav-overlay__list { margin: 0; padding: 0; list-style: none; } .nav-overlay__item { opacity: 0; transform: translateY(20px); transition: all .6s; } .nav-overlay.active .nav-overlay__item { opacity: 1; transform: translateY(0); } .nav-overlay.active .nav-overlay__item:nth-child(1) { transition-delay: 0.1s; } .nav-overlay.active .nav-overlay__item:nth-child(2) { transition-delay: 0.2s; } .nav-overlay.active .nav-overlay__item:nth-child(3) { transition-delay: 0.3s; } .nav-overlay.active .nav-overlay__item:nth-child(4) { transition-delay: 0.4s; } .nav-overlay__link { display: inline-block; padding: 20px; color: #fff; font-size: 24px; text-decoration: none; transition: color .3s; } .nav-overlay__link:hover { color: #4a90e2; }// overlay-script.js document.addEventListener('DOMContentLoaded', () => { const hamburger = document.querySelector('.hamburger-overlay'); const nav = document.querySelector('.nav-overlay'); hamburger.addEventListener('click', () => { hamburger.classList.toggle('active'); nav.classList.toggle('active'); const isOpen = hamburger.classList.contains('active'); hamburger.setAttribute('aria-expanded', isOpen); nav.setAttribute('aria-hidden', !isOpen); // メニューオープン時に背景スクロールを防止 document.body.style.overflow = isOpen ? 'hidden' : ''; }); // ESCキーでメニューを閉じる document.addEventListener('keydown', (e) => { if (e.key === 'Escape' && nav.classList.contains('active')) { hamburger.classList.remove('active'); nav.classList.remove('active'); hamburger.setAttribute('aria-expanded', false); nav.setAttribute('aria-hidden', true); document.body.style.overflow = ''; } }); });実装のポイント:- スムーズなオーバーレイ表示
- visibility と opacity の組み合わせによるスムーズな表示/非表示
- transition-delay を使用したメニュー項目の段階的な表示
- アクセシビリティ強化
- ESCキーでのメニュー閉じる機能
- スクロール制御による背景固定
- キーボード操作のサポート
- 視覚的な工夫
- メニュー項目の段階的なフェードイン
- ホバー時のインタラクション
- 背景の透過による奥行き表現
パターン3:モーフィングアニメーションメニュー
<div class="header"> <button class="hamburger-morph" aria-label="メニュー" aria-controls="morph-menu" aria-expanded="false"> <svg class="hamburger-morph__icon" width="48" height="48" viewBox="0 0 100 100"> <path class="hamburger-morph__line" d="M 20,29 H 80 C 80,29 94.5,28.817352 94.532987,66.711331 94.543142,77.980673 90.966081,81.670246 85.259173,81.668997 79.552261,81.667751 75.000211,74.999942 75.000211,74.999942 L 25.000021,25.000058" /> <path class="hamburger-morph__line" d="M 20,50 H 80" /> <path class="hamburger-morph__line" d="M 20,71 H 80 C 80,71 94.5,71.182648 94.532987,33.288669 94.543142,22.019327 90.966081,18.329754 85.259173,18.331003 79.552261,18.332249 75.000211,25.000058 75.000211,25.000058 L 25.000021,74.999942" /> </svg> </button> <nav id="morph-menu" class="nav-morph" aria-hidden="true"> <div class="nav-morph__wrapper"> <ul class="nav-morph__list"> <li class="nav-morph__item"> <a href="#" class="nav-morph__link"> <span class="nav-morph__text">Home</span> <span class="nav-morph__hover">ホーム</span> </a> </li> <li class="nav-morph__item"> <a href="#" class="nav-morph__link"> <span class="nav-morph__text">About</span> <span class="nav-morph__hover">私たちについて</span> </a> </li> <li class="nav-morph__item"> <a href="#" class="nav-morph__link"> <span class="nav-morph__text">Works</span> <span class="nav-morph__hover">制作実績</span> </a> </li> <li class="nav-morph__item"> <a href="#" class="nav-morph__link"> <span class="nav-morph__text">Contact</span> <span class="nav-morph__hover">お問い合わせ</span> </a> </li> </ul> </div> </nav> </div>.hamburger-morph { position: fixed; top: 20px; right: 20px; z-index: 1000; width: 48px; height: 48px; padding: 0; border: none; background: transparent; cursor: pointer; } .hamburger-morph__icon { width: 100%; height: 100%; } .hamburger-morph__line { fill: none; stroke: #000; stroke-width: 6; transition: stroke-dasharray 600ms cubic-bezier(0.4, 0, 0.2, 1), stroke-dashoffset 600ms cubic-bezier(0.4, 0, 0.2, 1); } .hamburger-morph__line:nth-child(1) { stroke-dasharray: 60 207; } .hamburger-morph__line:nth-child(2) { stroke-dasharray: 60 60; } .hamburger-morph__line:nth-child(3) { stroke-dasharray: 60 207; } .hamburger-morph.active .hamburger-morph__line:nth-child(1) { stroke-dasharray: 90 207; stroke-dashoffset: -134; } .hamburger-morph.active .hamburger-morph__line:nth-child(2) { stroke-dasharray: 1 60; stroke-dashoffset: -30; } .hamburger-morph.active .hamburger-morph__line:nth-child(3) { stroke-dasharray: 90 207; stroke-dashoffset: -134; } .nav-morph { position: fixed; top: 0; left: 0; width: 100%; height: 100vh; background: rgba(29, 29, 31, 0.98); clip-path: circle(0% at calc(100% - 44px) 44px); transition: clip-path 0.7s cubic-bezier(0.4, 0, 0.2, 1); z-index: 900; } .nav-morph.active { clip-path: circle(150% at calc(100% - 44px) 44px); } .nav-morph__wrapper { display: flex; align-items: center; justify-content: center; width: 100%; height: 100%; } .nav-morph__list { margin: 0; padding: 0; list-style: none; text-align: center; } .nav-morph__item { opacity: 0; transform: translateY(30px); transition: opacity 0.4s ease, transform 0.4s ease; } .nav-morph.active .nav-morph__item { opacity: 1; transform: translateY(0); } .nav-morph.active .nav-morph__item:nth-child(1) { transition-delay: 0.3s; } .nav-morph.active .nav-morph__item:nth-child(2) { transition-delay: 0.4s; } .nav-morph.active .nav-morph__item:nth-child(3) { transition-delay: 0.5s; } .nav-morph.active .nav-morph__item:nth-child(4) { transition-delay: 0.6s; } .nav-morph__link { position: relative; display: inline-block; padding: 20px; font-size: 28px; color: #fff; text-decoration: none; overflow: hidden; } .nav-morph__text, .nav-morph__hover { display: block; transition: transform 0.3s ease; } .nav-morph__hover { position: absolute; top: 100%; left: 0; width: 100%; transform: translateY(0%); } .nav-morph__link:hover .nav-morph__text { transform: translateY(-100%); } .nav-morph__link:hover .nav-morph__hover { transform: translateY(-100%); }document.addEventListener('DOMContentLoaded', () => { const hamburger = document.querySelector('.hamburger-morph'); const nav = document.querySelector('.nav-morph'); hamburger.addEventListener('click', () => { hamburger.classList.toggle('active'); nav.classList.toggle('active'); const isOpen = hamburger.classList.contains('active'); hamburger.setAttribute('aria-expanded', isOpen); nav.setAttribute('aria-hidden', !isOpen); document.body.style.overflow = isOpen ? 'hidden' : ''; }); // メニューリンクのホバーエフェクト用のイベントリスナー const menuLinks = document.querySelectorAll('.nav-morph__link'); menuLinks.forEach(link => { link.addEventListener('mouseenter', () => { link.querySelector('.nav-morph__text').style.transform = 'translateY(-100%)'; link.querySelector('.nav-morph__hover').style.transform = 'translateY(-100%)'; }); link.addEventListener('mouseleave', () => { link.querySelector('.nav-morph__text').style.transform = 'translateY(0)'; link.querySelector('.nav-morph__hover').style.transform = 'translateY(0)'; }); }); });実装のポイント:- SVGを使用したモーフィングアニメーション
- stroke-dasharray と stroke-dashoffset を使用した滑らかな変形
- cubic-bezier による緩急のある動き
- クリエイティブなメニュー展開
- clip-path を使用した円形展開アニメーション
- 順次表示されるメニュー項目
- インタラクティブな要素
- 二重テキストによるホバーエフェクト
- スムーズなテキストスライド
パターン4:スライド&フェードメニュー
<div class="header"> <button class="hamburger-fade" aria-label="メニュー" aria-controls="fade-menu" aria-expanded="false"> <div class="hamburger-fade__wrapper"> <span class="hamburger-fade__line"></span> <span class="hamburger-fade__line"></span> <span class="hamburger-fade__line"></span> </div> </button> <nav id="fade-menu" class="nav-fade" aria-hidden="true"> <div class="nav-fade__bg"></div> <div class="nav-fade__wrapper"> <ul class="nav-fade__list"> <li class="nav-fade__item"> <span class="nav-fade__number">01</span> <a href="#" class="nav-fade__link">Home</a> </li> <li class="nav-fade__item"> <span class="nav-fade__number">02</span> <a href="#" class="nav-fade__link">About</a> </li> <li class="nav-fade__item"> <span class="nav-fade__number">03</span> <a href="#" class="nav-fade__link">Works</a> </li> <li class="nav-fade__item"> <span class="nav-fade__number">04</span> <a href="#" class="nav-fade__link">Contact</a> </li> </ul> <div class="nav-fade__info"> <p class="nav-fade__address">東京都渋谷区○○ 1-2-3</p> <p class="nav-fade__tel">03-1234-5678</p> </div> </div> </nav> </div>/* fade-styles.css */ .hamburger-fade { position: fixed; top: 20px; right: 20px; z-index: 1000; width: 60px; height: 60px; padding: 0; border: none; background: transparent; cursor: pointer; } .hamburger-fade__wrapper { position: relative; width: 30px; height: 20px; margin: 20px auto; } .hamburger-fade__line { position: absolute; left: 0; width: 100%; height: 2px; background-color: #333; transition: all 0.5s cubic-bezier(0.23, 1, 0.32, 1); } .hamburger-fade__line:nth-child(1) { top: 0; } .hamburger-fade__line:nth-child(2) { top: 9px; } .hamburger-fade__line:nth-child(3) { top: 18px; } .hamburger-fade.active .hamburger-fade__line { background-color: #fff; } .hamburger-fade.active .hamburger-fade__line:nth-child(1) { transform: translateY(9px) rotate(45deg); } .hamburger-fade.active .hamburger-fade__line:nth-child(2) { opacity: 0; transform: translateX(20px); } .hamburger-fade.active .hamburger-fade__line:nth-child(3) { transform: translateY(-9px) rotate(-45deg); } .nav-fade { position: fixed; top: 0; left: 0; width: 100%; height: 100vh; visibility: hidden; z-index: 900; } .nav-fade__bg { position: absolute; top: 0; left: 0; width: 100%; height: 100%; background-color: rgba(0, 0, 0, 0.95); opacity: 0; transition: opacity 0.5s cubic-bezier(0.23, 1, 0.32, 1); } .nav-fade.active { visibility: visible; } .nav-fade.active .nav-fade__bg { opacity: 1; } .nav-fade__wrapper { position: relative; display: flex; flex-direction: column; justify-content: center; width: 100%; height: 100%; padding: 5vh 10vw; } .nav-fade__list { margin: 0; padding: 0; list-style: none; } .nav-fade__item { position: relative; margin-bottom: 2vh; padding-left: 60px; opacity: 0; transform: translateY(20px); transition: all 0.5s cubic-bezier(0.23, 1, 0.32, 1); } .nav-fade.active .nav-fade__item { opacity: 1; transform: translateY(0); } .nav-fade.active .nav-fade__item:nth-child(1) { transition-delay: 0.2s; } .nav-fade.active .nav-fade__item:nth-child(2) { transition-delay: 0.3s; } .nav-fade.active .nav-fade__item:nth-child(3) { transition-delay: 0.4s; } .nav-fade.active .nav-fade__item:nth-child(4) { transition-delay: 0.5s; } .nav-fade__number { position: absolute; left: 0; color: #666; font-size: 14px; font-family: 'Roboto', sans-serif; } .nav-fade__link { display: inline-block; color: #fff; font-size: 32px; text-decoration: none; transition: color 0.3s ease; } .nav-fade__link:hover { color: #4a90e2; } .nav-fade__info { margin-top: auto; padding-left: 60px; color: #666; font-size: 14px; opacity: 0; transform: translateY(20px); transition: all 0.5s cubic-bezier(0.23, 1, 0.32, 1) 0.6s; } .nav-fade.active .nav-fade__info { opacity: 1; transform: translateY(0); } .nav-fade__address, .nav-fade__tel { margin: 5px 0; } @media (max-width: 768px) { .nav-fade__link { font-size: 24px; } .nav-fade__item { padding-left: 40px; margin-bottom: 1.5vh; } .nav-fade__info { padding-left: 40px; } }// fade-script.js document.addEventListener('DOMContentLoaded', () => { const hamburger = document.querySelector('.hamburger-fade'); const nav = document.querySelector('.nav-fade'); hamburger.addEventListener('click', () => { hamburger.classList.toggle('active'); nav.classList.toggle('active'); const isOpen = hamburger.classList.contains('active'); hamburger.setAttribute('aria-expanded', isOpen); nav.setAttribute('aria-hidden', !isOpen); document.body.style.overflow = isOpen ? 'hidden' : ''; }); // メニューリンクにホバーエフェクトを追加 const menuLinks = document.querySelectorAll('.nav-fade__link'); menuLinks.forEach(link => { link.addEventListener('mouseover', () => { const number = link.parentElement.querySelector('.nav-fade__number'); number.style.color = '#4a90e2'; }); link.addEventListener('mouseout', () => { const number = link.parentElement.querySelector('.nav-fade__number'); number.style.color = '#666'; }); }); });実装のポイント:- 高級感のある演出
- 番号とテキストの組み合わせ
- 連続的なアニメーション
- 洗練された配色
- レスポンシブ対応
- フォントサイズの可変
- パディングの調整
- メディアクエリによる最適化
- インタラクティブ要素
- 番号とリンクの連動したホバーエフェクト
- スムーズなフェードイン
- 背景のオーバーレイ効果
パターン5:グリッドアニメーションメニュー
<div class="header"> <button class="hamburger-grid" aria-label="メニュー" aria-controls="grid-menu" aria-expanded="false"> <div class="hamburger-grid__dots"> <span class="hamburger-grid__dot"></span> <span class="hamburger-grid__dot"></span> <span class="hamburger-grid__dot"></span> <span class="hamburger-grid__dot"></span> <span class="hamburger-grid__dot"></span> <span class="hamburger-grid__dot"></span> <span class="hamburger-grid__dot"></span> <span class="hamburger-grid__dot"></span> <span class="hamburger-grid__dot"></span> </div> </button> <nav id="grid-menu" class="nav-grid" aria-hidden="true"> <div class="nav-grid__content"> <div class="nav-grid__sections"> <section class="nav-grid__section"> <h2 class="nav-grid__title">Menu</h2> <ul class="nav-grid__list"> <li><a href="#" class="nav-grid__link">Home</a></li> <li><a href="#" class="nav-grid__link">About</a></li> <li><a href="#" class="nav-grid__link">Works</a></li> <li><a href="#" class="nav-grid__link">Contact</a></li> </ul> </section> <section class="nav-grid__section"> <h2 class="nav-grid__title">Social</h2> <ul class="nav-grid__list"> <li><a href="#" class="nav-grid__link">Twitter</a></li> <li><a href="#" class="nav-grid__link">Instagram</a></li> <li><a href="#" class="nav-grid__link">GitHub</a></li> </ul> </section> </div> </div> </nav> </div>.hamburger-grid { position: fixed; top: 20px; right: 20px; z-index: 1000; width: 50px; height: 50px; padding: 10px; border: none; background: transparent; cursor: pointer; } .hamburger-grid__dots { display: grid; grid-template-columns: repeat(3, 1fr); gap: 4px; width: 100%; height: 100%; } .hamburger-grid__dot { width: 100%; height: 100%; background-color: #333; border-radius: 50%; transition: transform 0.3s ease, background-color 0.3s ease; } .hamburger-grid.active .hamburger-grid__dot { background-color: #fff; } .hamburger-grid.active .hamburger-grid__dot:nth-child(1) { transform: scale(0); } .hamburger-grid.active .hamburger-grid__dot:nth-child(2) { transform: translateY(8px); } .hamburger-grid.active .hamburger-grid__dot:nth-child(3) { transform: scale(0); } .hamburger-grid.active .hamburger-grid__dot:nth-child(4) { transform: translateX(8px); } .hamburger-grid.active .hamburger-grid__dot:nth-child(5) { transform: scale(1.2); } .hamburger-grid.active .hamburger-grid__dot:nth-child(6) { transform: translateX(-8px); } .hamburger-grid.active .hamburger-grid__dot:nth-child(7) { transform: scale(0); } .hamburger-grid.active .hamburger-grid__dot:nth-child(8) { transform: translateY(-8px); } .hamburger-grid.active .hamburger-grid__dot:nth-child(9) { transform: scale(0); } .nav-grid { position: fixed; top: 0; left: 0; width: 100%; height: 100vh; background-color: #1a1a1a; visibility: hidden; opacity: 0; transition: all 0.5s cubic-bezier(0.4, 0, 0.2, 1); z-index: 900; } .nav-grid.active { visibility: visible; opacity: 1; } .nav-grid__content { display: grid; grid-template-columns: repeat(12, 1fr); gap: 20px; max-width: 1200px; height: 100%; margin: 0 auto; padding: 100px 40px; } .nav-grid__sections { grid-column: span 12; display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap: 40px; } .nav-grid__section { opacity: 0; transform: translateY(20px); transition: all 0.5s cubic-bezier(0.4, 0, 0.2, 1); } .nav-grid.active .nav-grid__section { opacity: 1; transform: translateY(0); } .nav-grid.active .nav-grid__section:nth-child(1) { transition-delay: 0.2s; } .nav-grid.active .nav-grid__section:nth-child(2) { transition-delay: 0.3s; } .nav-grid__title { margin: 0 0 20px; color: #666; font-size: 14px; text-transform: uppercase; letter-spacing: 2px; } .nav-grid__list { margin: 0; padding: 0; list-style: none; } .nav-grid__list li { margin-bottom: 15px; overflow: hidden; } .nav-grid__link { display: inline-block; color: #fff; font-size: 24px; text-decoration: none; transform: translateY(100%); transition: transform 0.5s cubic-bezier(0.4, 0, 0.2, 1), color 0.3s ease; } .nav-grid.active .nav-grid__link { transform: translateY(0); } .nav-grid__link:hover { color: #4a90e2; } @media (max-width: 768px) { .nav-grid__content { padding: 80px 20px; } .nav-grid__sections { grid-template-columns: 1fr; } .nav-grid__link { font-size: 20px; } }document.addEventListener('DOMContentLoaded', () => { const hamburger = document.querySelector('.hamburger-grid'); const nav = document.querySelector('.nav-grid'); const links = document.querySelectorAll('.nav-grid__link'); hamburger.addEventListener('click', () => { hamburger.classList.toggle('active'); nav.classList.toggle('active'); const isOpen = hamburger.classList.contains('active'); hamburger.setAttribute('aria-expanded', isOpen); nav.setAttribute('aria-hidden', !isOpen); document.body.style.overflow = isOpen ? 'hidden' : ''; // リンクのアニメーションディレイを設定 if (isOpen) { links.forEach((link, index) => { link.style.transitionDelay = `${0.2 + (index * 0.1)}s`; }); } else { links.forEach(link => { link.style.transitionDelay = '0s'; }); } }); // アクセシビリティのためのキーボードナビゲーション nav.addEventListener('keydown', (e) => { if (e.key === 'Escape' && nav.classList.contains('active')) { hamburger.click(); } }); });実装のポイント:- グリッドレイアウトの活用
- CSS Gridによる柔軟なレイアウト
- レスポンシブ対応の簡略化
- セクション分けによる整理された構造
- ドットアニメーション
- 個別のドットの動きによる視覚的な楽しさ
- スケールと移動を組み合わせた演出
- 滑らかな色の変化
- 段階的なアニメーション
- セクションごとの表示タイミング制御
- リンクの順次表示
- スムーズな出現と消失
さいごに
ここまで5種類のモダンなハンバーガーメニューの実装方法をご紹介してきました。
それぞれのデザインや動きの特徴を活かして、サイトの雰囲気に合わせて使い分けてください。