US 04-05: Responsive Navigation und Startseitenlink ergänzt

Mobiles Menü mit Tastaturbedienung, Hintergrund und passenden Sprungabständen ergänzt. Logo abgerundet und mit der Startseite verlinkt. Kontakt bleibt vorerst deaktiviert; das neue Supportbild liegt im Bilderordner bereit.
S-V-Navigation
3015418 2026-09-29 16:42:38 +02:00
parent 39952a0c36
commit 1ba8844415
4 changed files with 212 additions and 41 deletions

View File

@ -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 { :root {
--navigation-height: 99px; --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; .site-navigation {
--font-body: "Inter", system-ui, sans-serif; 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, .site-navigation,
@ -24,18 +31,6 @@
box-sizing: border-box; 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 { .site-navigation__bar {
display: flex; display: flex;
align-items: center; align-items: center;
@ -44,13 +39,13 @@
width: min(1680px, calc(100% - clamp(40px, 10vw, 192px))); width: min(1680px, calc(100% - clamp(40px, 10vw, 192px)));
margin-inline: auto; margin-inline: auto;
} }
.site-navigation .brand { .site-navigation .brand {
display: flex; display: flex;
align-items: center; align-items: center;
gap: 20px; gap: 20px;
width: min(1680px, calc(100% - clamp(40px, 10vw, 192px))); min-width: 0;
min-height: calc(var(--navigation-height) - 3px); min-height: calc(var(--navigation-height) - 3px);
margin-inline: auto;
padding-block: 8px; padding-block: 8px;
} }
@ -62,26 +57,34 @@
padding: 0; padding: 0;
list-style: none; list-style: none;
} }
.site-navigation__links a { .site-navigation__links a,
.site-navigation .navigation-disabled {
display: block;
padding-block: 10px;
color: var(--text-muted); color: var(--text-muted);
font-size: 15px; font-size: 15px;
font-weight: 600; font-weight: 600;
text-decoration: none; text-decoration: none;
transition: color 0.15s ease; white-space: nowrap;
} }
.site-navigation__links a:hover, .site-navigation__links a:hover,
.site-navigation__links a:focus-visible { .site-navigation__links a:focus-visible {
color: var(--text-primary); 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: 2px solid var(--accent);
outline-offset: 4px; outline-offset: 4px;
border-radius: 4px; border-radius: 4px;
} }
.site-navigation .navigation-disabled {
opacity: 0.5;
cursor: default;
}
.site-navigation .brand__logo { .site-navigation .brand__logo {
display: grid; display: grid;
@ -90,6 +93,7 @@
width: 60px; width: 60px;
height: 60px; height: 60px;
border-radius: 22px; border-radius: 22px;
overflow: hidden;
background: var(--text-primary); background: var(--text-primary);
} }
@ -98,6 +102,12 @@
width: 60px; width: 60px;
height: 60px; height: 60px;
object-fit: contain; object-fit: contain;
border-radius: inherit;
}
.site-navigation .brand__logo:focus-visible {
outline: 2px solid var(--accent);
outline-offset: 4px;
} }
.site-navigation .brand__text { .site-navigation .brand__text {
@ -116,17 +126,101 @@
} }
.site-navigation .brand__label { .site-navigation .brand__label {
color: var(--text-muted2); color: var(--text-muted);
font-size: 17px; font-size: 17px;
font-weight: 600; font-weight: 600;
line-height: 1.4; 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) { @media (max-width: 700px) {
:root { :root {
--navigation-height: 81px; --navigation-height: 81px;
} }
.site-navigation__bar {
gap: 12px;
}
.site-navigation .brand { .site-navigation .brand {
gap: 12px; gap: 12px;
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 MiB

View File

@ -16,6 +16,7 @@
<link rel="stylesheet" href="css/leistungen.css"> <link rel="stylesheet" href="css/leistungen.css">
<link rel="stylesheet" href="css/berater.css"> <link rel="stylesheet" href="css/berater.css">
<link rel="stylesheet" href="css/beratung.css"> <link rel="stylesheet" href="css/beratung.css">
<script src="js/navigation.js" defer></script>
<script src="js/leistungen.js" defer></script> <script src="js/leistungen.js" defer></script>
<script src="js/berater.js" defer></script> <script src="js/berater.js" defer></script>
<script src="js/beratung.js" defer></script> <script src="js/beratung.js" defer></script>
@ -26,24 +27,27 @@
<header class="site-navigation"> <header class="site-navigation">
<div class="site-navigation__bar"> <div class="site-navigation__bar">
<div class="brand"> <div class="brand">
<div class="brand__logo"> <a class="brand__logo" href="https://tri-hub.de/" aria-label="Zur Trihub-Startseite">
<img src="images/trihub-logo.jpg" alt="Trihub – fit und vital ab 50!" width="500" height="500"> <img src="images/trihub-logo.jpg" alt="Trihub – fit und vital ab 50!" width="500" height="500">
</div> </a>
<div class="brand__text"> <div class="brand__text">
<span class="brand__name">TRI-HUB</span> <span class="brand__name">TRI-HUB</span>
<span class="brand__label">Triathlon als sportliches Zuhause ab 50</span> <span class="brand__label">Triathlon als sportliches Zuhause ab 50</span>
</div> </div>
</div> </div>
<nav class="site-navigation__links" aria-label="Hauptnavigation"> <button class="menu-toggle" type="button" aria-controls="navigation-links"
aria-expanded="false" aria-label="Menü öffnen">☰</button>
<nav class="site-navigation__links" id="navigation-links" aria-label="Hauptnavigation">
<ul> <ul>
<li><a href="#produktuebersicht">Übersicht</a></li> <li><a href="#produktuebersicht">Übersicht</a></li>
<li><a href="#leistungen">Pakete</a></li> <li><a href="#leistungen">Pakete</a></li>
<li><a href="#berater">Berater</a></li> <li><a href="#berater">Berater</a></li>
<li><a href="#beratung">Infos</a></li> <li><a href="#beratung">Infos</a></li>
<li><a href="#kontakt">Kontakt</a></li> <li><span class="navigation-disabled" aria-disabled="true">Kontakt</span></li>
</ul> </ul>
</nav> </nav>
</div> </div>
<div class="site-navigation__backdrop" aria-hidden="true"></div>
</header> </header>
<main id="main-content"> <main id="main-content">

73
js/navigation.js 100644
View File

@ -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);
})();