diff --git a/css/navigation.css b/css/navigation.css index 3e078a6..fbd21af 100644 --- a/css/navigation.css +++ b/css/navigation.css @@ -1,22 +1,29 @@ -/* Shahnam und Vincent: Gemeinsame Kopfzeile für US 04-05. */ +/* Shahnam und Vincent: Gemeinsame Navigation für US 04-05. */ :root { --navigation-height: 99px; + scroll-padding-top: calc(var(--navigation-offset, var(--navigation-height)) + 16px); } -.site-navigation { -/* Werte per Pixel-Sampling aus dem Referenz-Screenshot (Produktübersicht) übernommen */ - --background: #071419; /* früher "bg-dark */ - --background-rgb: 7 20 25; /* gleiche Basisfarbe wie --background, - aber ohne fixes Alpha – für Gradient-Stops - wird benutzt um Bildern einen gradient zu verpassen */ - --background-panel: #152027; /* früher "primary */ - --accent: #4597A3; - --accent-soft: rgba(69, 151, 163, 0.14); - --text-primary: #ffffff; - --text-muted: #7e858a; - --text-muted2: #b7bec2; - --font-display: "Sora", "Inter", system-ui, sans-serif; - --font-body: "Inter", system-ui, sans-serif; +.site-navigation { + color-scheme: dark; + --background: #071419; + --background-panel: #152027; + --accent: #4597a3; + --accent-soft: rgb(69 151 163 / 14%); + --text-primary: #fff; + --text-muted: #b7bec2; + --border: rgb(255 255 255 / 16%); + + /* Bleibt beim Scrollen sichtbar und behält ihren Platz im Layout. */ + position: sticky; + top: 0; + z-index: 100; + border-top: 3px solid var(--background); + background: var(--background); + color: var(--text-primary); + font-family: system-ui, -apple-system, "Segoe UI", Arial, sans-serif; + line-height: 1.6; + box-shadow: 0 4px 16px rgb(0 0 0 / 16%); } .site-navigation, @@ -24,18 +31,6 @@ box-sizing: border-box; } -.site-navigation { - /* Bleibt über alle Seitenbereiche hinweg oben sichtbar und behält ihren Platz im Layout. */ - position: sticky; - top: 0; - z-index: 100; - border-top: 3px solid var(--accent); - background: var(--background); - color: var(--text-primary); - font-family: system-ui, -apple-system, "Segoe UI", Arial, sans-serif; - line-height: 1.6; - box-shadow: 0 4px 16px rgb(0 0 0 / 16%); -} .site-navigation__bar { display: flex; align-items: center; @@ -44,13 +39,13 @@ width: min(1680px, calc(100% - clamp(40px, 10vw, 192px))); margin-inline: auto; } + .site-navigation .brand { display: flex; align-items: center; gap: 20px; - width: min(1680px, calc(100% - clamp(40px, 10vw, 192px))); + min-width: 0; min-height: calc(var(--navigation-height) - 3px); - margin-inline: auto; padding-block: 8px; } @@ -62,26 +57,34 @@ padding: 0; list-style: none; } - -.site-navigation__links a { + +.site-navigation__links a, +.site-navigation .navigation-disabled { + display: block; + padding-block: 10px; color: var(--text-muted); font-size: 15px; font-weight: 600; text-decoration: none; - transition: color 0.15s ease; + white-space: nowrap; } - + .site-navigation__links a:hover, .site-navigation__links a:focus-visible { color: var(--text-primary); } - -.site-navigation__links a:focus-visible { + +.site-navigation__links a:focus-visible, +.site-navigation .menu-toggle:focus-visible { outline: 2px solid var(--accent); outline-offset: 4px; border-radius: 4px; } - + +.site-navigation .navigation-disabled { + opacity: 0.5; + cursor: default; +} .site-navigation .brand__logo { display: grid; @@ -90,6 +93,7 @@ width: 60px; height: 60px; border-radius: 22px; + overflow: hidden; background: var(--text-primary); } @@ -98,6 +102,12 @@ width: 60px; height: 60px; object-fit: contain; + border-radius: inherit; +} + +.site-navigation .brand__logo:focus-visible { + outline: 2px solid var(--accent); + outline-offset: 4px; } .site-navigation .brand__text { @@ -116,17 +126,101 @@ } .site-navigation .brand__label { - color: var(--text-muted2); + color: var(--text-muted); font-size: 17px; font-weight: 600; line-height: 1.4; } +.site-navigation .menu-toggle { + display: none; + flex-shrink: 0; + align-items: center; + justify-content: center; + width: 44px; + height: 44px; + padding: 0; + border: 1px solid var(--border); + border-radius: 10px; + background: transparent; + color: var(--text-primary); + font: inherit; + font-size: 26px; + line-height: 1; + cursor: pointer; +} + +.site-navigation .menu-toggle:hover { + background: var(--accent-soft); +} + +.site-navigation__backdrop { + display: none; +} + +/* Der gleiche Grenzwert wird in navigation.js verwendet. */ +@media (max-width: 1100px) { + .site-navigation .menu-toggle { + display: inline-flex; + } + + .site-navigation__links { + display: none; + position: absolute; + z-index: 2; + top: 100%; + right: 0; + width: min(360px, 100%); + max-height: calc(100vh - var(--navigation-offset, var(--navigation-height))); + max-height: calc(100dvh - var(--navigation-offset, var(--navigation-height))); + overflow-y: auto; + overscroll-behavior: contain; + padding: 16px 24px 24px; + border: 1px solid var(--border); + border-top: 0; + border-radius: 0 0 0 16px; + background: var(--background); + box-shadow: -8px 12px 24px rgb(0 0 0 / 20%); + } + + .site-navigation__links ul { + align-items: stretch; + flex-direction: column; + gap: 4px; + } + + .site-navigation__links a, + .site-navigation .navigation-disabled { + padding: 12px 16px; + border-radius: 8px; + } + + .site-navigation__links a:hover { + background: var(--accent-soft); + } + + .site-navigation.is-open .site-navigation__links, + .site-navigation.is-open .site-navigation__backdrop { + display: block; + } + + .site-navigation__backdrop { + position: fixed; + z-index: 1; + inset: var(--navigation-offset, var(--navigation-height)) 0 0; + background: rgb(0 0 0 / 45%); + } +} + @media (max-width: 700px) { :root { --navigation-height: 81px; } + .site-navigation__bar { + gap: 12px; + } + .site-navigation .brand { gap: 12px; } diff --git a/images/contact-support-trihub.png b/images/contact-support-trihub.png new file mode 100644 index 0000000..3efa1da Binary files /dev/null and b/images/contact-support-trihub.png differ diff --git a/index.html b/index.html index 6a4b692..c0e6deb 100644 --- a/index.html +++ b/index.html @@ -16,6 +16,7 @@ + @@ -26,24 +27,27 @@ - + - + TRI-HUB Triathlon als sportliches Zuhause ab 50 - + ☰ + Übersicht Pakete Berater Infos - Kontakt + Kontakt + diff --git a/js/navigation.js b/js/navigation.js new file mode 100644 index 0000000..1a0f202 --- /dev/null +++ b/js/navigation.js @@ -0,0 +1,73 @@ +(() => { + const navigation = document.querySelector('.site-navigation'); + if (!navigation) return; + + const button = navigation.querySelector('.menu-toggle'); + const links = navigation.querySelector('#navigation-links'); + const backdrop = navigation.querySelector('.site-navigation__backdrop'); + if (!button || !links || !backdrop) return; + + // Muss zum Grenzwert in navigation.css passen. + const mobileView = window.matchMedia('(max-width: 1100px)'); + + function setMenuOpen(isOpen) { + isOpen = isOpen && mobileView.matches; + navigation.classList.toggle('is-open', isOpen); + button.setAttribute('aria-expanded', String(isOpen)); + button.setAttribute('aria-label', isOpen ? 'Menü schließen' : 'Menü öffnen'); + button.textContent = isOpen ? '✕' : '☰'; + } + + button.addEventListener('click', () => { + setMenuOpen(button.getAttribute('aria-expanded') !== 'true'); + }); + + // Nach einem Sprung bleibt der Tastaturfokus im gewählten Bereich. + links.addEventListener('click', (event) => { + const link = event.target.closest('a'); + if (!link || !mobileView.matches) return; + setMenuOpen(false); + const target = document.querySelector(link.getAttribute('href')); + if (target) { + const hadTabindex = target.hasAttribute('tabindex'); + if (!hadTabindex) target.setAttribute('tabindex', '-1'); + requestAnimationFrame(() => target.focus({ preventScroll: true })); + if (!hadTabindex) { + target.addEventListener('blur', () => target.removeAttribute('tabindex'), { once: true }); + } + } + }); + + document.addEventListener('keydown', (event) => { + if (event.key === 'Escape' && button.getAttribute('aria-expanded') === 'true') { + setMenuOpen(false); + button.focus(); + } + }); + + backdrop.addEventListener('click', () => { + setMenuOpen(false); + button.focus(); + }); + + // Das Menü bleibt beim Weitergehen mit Tab nicht über dem Seiteninhalt liegen. + navigation.addEventListener('focusout', (event) => { + if (!navigation.contains(event.relatedTarget)) setMenuOpen(false); + }); + + mobileView.addEventListener('change', () => { + const focusedElement = document.activeElement; + setMenuOpen(false); + if (mobileView.matches && links.contains(focusedElement)) button.focus(); + if (!mobileView.matches && focusedElement === button) links.querySelector('a')?.focus(); + }); + + // Berücksichtigt auch umgebrochene Texte und vergrößerte Schrift. + const headerObserver = new ResizeObserver(() => { + document.documentElement.style.setProperty( + '--navigation-offset', `${navigation.getBoundingClientRect().height}px` + ); + }); + headerObserver.observe(navigation); + setMenuOpen(false); +})();