feat(nav): add hamburger menu for mobile navigation (Fix #27)
All checks were successful
Deploy Feature Branch to Test / deploy (push) Successful in 24s
All checks were successful
Deploy Feature Branch to Test / deploy (push) Successful in 24s
- Hamburger button with animated X toggle (CSS-only icon) - Slide-down mobile nav on ≤900px with 44px+ tap targets - Semi-transparent overlay when menu is open - Escape key + outside click + link click closes menu - Auto-close on resize to desktop - Desktop navigation unchanged - Pure vanilla JS toggle, no jQuery dependency
This commit is contained in:
@@ -115,6 +115,84 @@ nav.scrolled .nav-links a:hover {
|
||||
box-shadow: 0 4px 20px rgb(139 105 20 / 50%);
|
||||
}
|
||||
|
||||
/* HAMBURGER */
|
||||
.nav-hamburger {
|
||||
display: none;
|
||||
width: 44px;
|
||||
height: 44px;
|
||||
background: none;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
z-index: 110;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.nav-hamburger span,
|
||||
.nav-hamburger span::before,
|
||||
.nav-hamburger span::after {
|
||||
display: block;
|
||||
width: 22px;
|
||||
height: 2px;
|
||||
background: var(--white);
|
||||
border-radius: 1px;
|
||||
transition:
|
||||
transform 0.3s ease,
|
||||
opacity 0.3s ease,
|
||||
background 0.4s;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.nav-hamburger span::before,
|
||||
.nav-hamburger span::after {
|
||||
content: "";
|
||||
}
|
||||
|
||||
.nav-hamburger span::before {
|
||||
transform: translateY(-7px);
|
||||
}
|
||||
|
||||
.nav-hamburger span::after {
|
||||
transform: translateY(7px);
|
||||
}
|
||||
|
||||
nav.scrolled .nav-hamburger span,
|
||||
nav.scrolled .nav-hamburger span::before,
|
||||
nav.scrolled .nav-hamburger span::after {
|
||||
background: var(--dark);
|
||||
}
|
||||
|
||||
.nav-hamburger.active span {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.nav-hamburger.active span::before {
|
||||
transform: rotate(45deg);
|
||||
background: var(--dark);
|
||||
}
|
||||
|
||||
.nav-hamburger.active span::after {
|
||||
transform: rotate(-45deg);
|
||||
background: var(--dark);
|
||||
}
|
||||
|
||||
.nav-mobile-overlay {
|
||||
display: none;
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
background: rgb(28 26 23 / 50%);
|
||||
z-index: 90;
|
||||
opacity: 0;
|
||||
transition: opacity 0.3s ease;
|
||||
}
|
||||
|
||||
.nav-mobile-overlay.active {
|
||||
display: block;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
/* HERO */
|
||||
.hero {
|
||||
position: relative;
|
||||
@@ -1042,6 +1120,59 @@ footer {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.nav-hamburger {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
/* Mobile slide-down nav */
|
||||
nav.mobile-open .nav-links {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background: rgb(253 252 250 / 98%);
|
||||
backdrop-filter: blur(12px);
|
||||
padding: 5rem 1.5rem 2rem;
|
||||
gap: 0;
|
||||
z-index: 95;
|
||||
border-bottom: 1px solid var(--warm);
|
||||
animation: slideDown 0.3s ease;
|
||||
}
|
||||
|
||||
nav.mobile-open .nav-links a {
|
||||
color: var(--charcoal);
|
||||
font-size: 1rem;
|
||||
padding: 1rem 0;
|
||||
border-bottom: 1px solid var(--warm);
|
||||
display: block;
|
||||
min-height: 44px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
nav.mobile-open .nav-hamburger span,
|
||||
nav.mobile-open .nav-hamburger span::before,
|
||||
nav.mobile-open .nav-hamburger span::after {
|
||||
background: var(--dark);
|
||||
}
|
||||
|
||||
nav.mobile-open .nav-hamburger.active span {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
@keyframes slideDown {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(-10px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
.hero-content {
|
||||
padding: 0 1.5rem 4rem;
|
||||
}
|
||||
|
||||
@@ -64,6 +64,9 @@
|
||||
<body>
|
||||
<nav id="navbar">
|
||||
<div class="nav-logo">Bahnhofstraße 10</div>
|
||||
<button class="nav-hamburger" aria-label="Navigation öffnen" aria-expanded="false">
|
||||
<span></span>
|
||||
</button>
|
||||
<ul class="nav-links">
|
||||
<li><a href="#galerie">Galerie</a></li>
|
||||
<li><a href="#grundriss">Grundriss</a></li>
|
||||
@@ -77,6 +80,7 @@
|
||||
Jetzt anfragen
|
||||
</button>
|
||||
</nav>
|
||||
<div class="nav-mobile-overlay" aria-hidden="true"></div>
|
||||
|
||||
<section class="hero" id="hero">
|
||||
<div
|
||||
|
||||
@@ -101,3 +101,48 @@ $(function () {
|
||||
$("#formSuccess").fadeIn(400);
|
||||
});
|
||||
});
|
||||
|
||||
// Mobile hamburger menu (vanilla JS)
|
||||
(function () {
|
||||
var hamburger = document.querySelector(".nav-hamburger");
|
||||
var nav = document.getElementById("navbar");
|
||||
var overlay = document.querySelector(".nav-mobile-overlay");
|
||||
var links = nav ? nav.querySelectorAll(".nav-links a") : [];
|
||||
|
||||
function toggleMenu() {
|
||||
var isOpen = hamburger.classList.toggle("active");
|
||||
nav.classList.toggle("mobile-open", isOpen);
|
||||
if (overlay) overlay.classList.toggle("active", isOpen);
|
||||
hamburger.setAttribute("aria-expanded", isOpen);
|
||||
document.body.style.overflow = isOpen ? "hidden" : "";
|
||||
}
|
||||
|
||||
function closeMenu() {
|
||||
hamburger.classList.remove("active");
|
||||
nav.classList.remove("mobile-open");
|
||||
if (overlay) overlay.classList.remove("active");
|
||||
hamburger.setAttribute("aria-expanded", "false");
|
||||
document.body.style.overflow = "";
|
||||
}
|
||||
|
||||
if (hamburger) {
|
||||
hamburger.addEventListener("click", toggleMenu);
|
||||
}
|
||||
|
||||
if (overlay) {
|
||||
overlay.addEventListener("click", closeMenu);
|
||||
}
|
||||
|
||||
links.forEach(function (link) {
|
||||
link.addEventListener("click", closeMenu);
|
||||
});
|
||||
|
||||
document.addEventListener("keydown", function (e) {
|
||||
if (e.key === "Escape") closeMenu();
|
||||
});
|
||||
|
||||
// Close on resize to desktop
|
||||
window.addEventListener("resize", function () {
|
||||
if (window.innerWidth > 900) closeMenu();
|
||||
});
|
||||
})();
|
||||
|
||||
Reference in New Issue
Block a user