Mobiles Menü als Drawer: oben verankert, Accordion statt Sprung
Das Overlay war vertikal zentriert. Beim Aufklappen eines Dropdowns wuchs die Liste und rezentrierte sich — der gerade angetippte Punkt sprang unter dem Finger weg, bei langen Menüs lief der Inhalt aus dem Screen (nicht scrollbar). Jetzt ist die Liste oben verankert (justify-content: flex-start, padding unter Header + Logo-Überhang) und scrollbar mit overscroll-behavior: contain. Punkte sind volle Tap-Breite mit Hairline-Trennern, Chevron rechtsbündig, aktive Seite mit rotem Balken links. Untermenüs animieren über die 0fr/1fr-Zeile des li-Grids statt display: none — weiches Auf-/Zuklappen ohne Layout-Sprung. Unterpunkte in Abel statt Coolvetica (unter 28px unleserlich, siehe CLAUDE.md), linksbündig, Desktop-Panel-Optik im Overlay komplett zurückgesetzt (inkl. backdrop-filter/radius/translateX, die sonst durchschlugen). nav.js setzt .site-nav--js auf die Nav: nur ohne JS öffnet :focus-within die Untermenüs. Mit JS wäre das ein Bug — der Button behält nach dem Tipp den Fokus, das Menü ließe sich nie wieder zuklappen. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MSsVdooFLgPA8gPFp7HwZU
This commit is contained in:
@@ -264,6 +264,12 @@
|
||||
z-index: 30;
|
||||
}
|
||||
|
||||
/* Logo/Brand ebenfalls über dem Overlay halten — Orientierung bei offenem Menü. */
|
||||
.site-header__brand {
|
||||
position: relative;
|
||||
z-index: 30;
|
||||
}
|
||||
|
||||
.site-nav {
|
||||
order: 3;
|
||||
margin-left: 0;
|
||||
@@ -317,59 +323,146 @@
|
||||
transform: translateY(-9px) rotate(-45deg);
|
||||
}
|
||||
|
||||
/* Overlay: oben verankert + scrollbar — beim Aufklappen eines Dropdowns bleibt
|
||||
der angetippte Punkt stehen (kein Re-Zentrier-Sprung), lange Menüs laufen
|
||||
nicht mehr aus dem Screen. */
|
||||
.site-nav__list {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
z-index: 20;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
gap: 1.75rem;
|
||||
background: rgb(0 0 0 / 0.91);
|
||||
font-size: var(--fs-700);
|
||||
justify-content: flex-start;
|
||||
align-items: stretch;
|
||||
gap: 0;
|
||||
overflow-y: auto;
|
||||
overscroll-behavior: contain;
|
||||
background: rgb(8 8 8 / 0.96);
|
||||
font-size: var(--fs-650);
|
||||
text-align: left;
|
||||
visibility: hidden;
|
||||
opacity: 0;
|
||||
transition: opacity var(--transition), visibility var(--transition);
|
||||
}
|
||||
|
||||
/* Padding separat mit (0,2,0): der reset-Selektor ul[class] (0,1,1) würde
|
||||
es auf der Ein-Klassen-Regel überschreiben. Links auf --container-pad,
|
||||
damit die Menüpunkte mit dem Logo fluchten. */
|
||||
.site-nav .site-nav__list {
|
||||
/* Oben: Header + Logo-Überhang (Logo ragt unter den Header) + Luft. */
|
||||
padding: calc(var(--header-h) + 4rem) var(--container-pad) 3rem;
|
||||
}
|
||||
|
||||
@supports (backdrop-filter: blur(1px)) {
|
||||
.site-nav__list {
|
||||
background: rgb(8 8 8 / 0.85);
|
||||
backdrop-filter: blur(18px) saturate(1.3);
|
||||
}
|
||||
}
|
||||
|
||||
.site-nav__list a:not(.btn) {
|
||||
font-family: var(--ff-heading);
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
/* Dropdown im Overlay: Trigger wie die anderen Punkte, Untermenü inline darunter. */
|
||||
.site-nav__sublink {
|
||||
font-family: var(--ff-heading);
|
||||
font-size: var(--fs-700);
|
||||
text-transform: uppercase;
|
||||
justify-content: center;
|
||||
/* Drawer-Zeilen: volle Tap-Breite mit Hairline-Trennern statt frei schwebender
|
||||
Punkte — Chevron sitzt rechtsbündig, aktive Seite bekommt den roten Balken
|
||||
links (die Desktop-Unterstreichung wird hier neutralisiert). Untermenü-Höhe
|
||||
animiert über die 0fr/1fr-Zeile des li-Grids (weicher Accordion-Effekt). */
|
||||
.site-nav__list > .site-nav__item {
|
||||
border-bottom: 1px solid var(--clr-glass-border);
|
||||
}
|
||||
|
||||
/* Im Overlay inline einklappen — display statt visibility, sonst bliebe Platz reserviert.
|
||||
Spezifität (0,2,0) gleich der Desktop-Regel; gewinnt hier per Quell-Reihenfolge. */
|
||||
.site-nav__list > .site-nav__item > a:not(.btn),
|
||||
.site-nav__sublink {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
width: 100%;
|
||||
padding: 1rem 0.25rem;
|
||||
border-bottom: 0;
|
||||
font-family: var(--ff-heading);
|
||||
font-size: var(--fs-650);
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.site-nav__list > .site-nav__item > a[aria-current="page"],
|
||||
.site-nav__sublink[data-current] {
|
||||
border-bottom: 0;
|
||||
box-shadow: inset 3px 0 0 var(--clr-accent);
|
||||
padding-left: 1rem;
|
||||
}
|
||||
|
||||
/* Volle Breite + zentrierter Text: Items und Untermenüs zentrieren sich am
|
||||
Screen (nicht am shrink-gewrappten li), Unterstreichungen bleiben textbreit. */
|
||||
.site-nav__item--has-submenu {
|
||||
display: grid;
|
||||
grid-template-rows: auto 0fr;
|
||||
transition: grid-template-rows var(--transition);
|
||||
}
|
||||
|
||||
.site-nav__item--has-submenu:has(> .site-nav__sublink[aria-expanded="true"]) {
|
||||
grid-template-rows: auto 1fr;
|
||||
}
|
||||
|
||||
/* Ohne JS gibt es kein aria-expanded-Toggling — dann (und nur dann) öffnet
|
||||
:focus-within. Mit JS wäre :focus-within ein Bug: der Button behält nach
|
||||
dem Tipp den Fokus, das Menü ließe sich nie wieder zuklappen. */
|
||||
.site-nav:not(.site-nav--js) .site-nav__item--has-submenu:focus-within {
|
||||
grid-template-rows: auto 1fr;
|
||||
}
|
||||
|
||||
/* Desktop-Panel-Optik komplett zurücksetzen (inkl. backdrop-filter/radius —
|
||||
sonst schimmert das Glas-Panel im Overlay durch). Spezifität (0,2,0) gleich
|
||||
der Desktop-Regel; gewinnt hier per Quell-Reihenfolge. */
|
||||
.site-nav__list .site-nav__submenu {
|
||||
position: static;
|
||||
transform: none;
|
||||
display: none;
|
||||
opacity: 1;
|
||||
visibility: visible;
|
||||
display: grid;
|
||||
min-height: 0;
|
||||
overflow: hidden;
|
||||
opacity: 0;
|
||||
visibility: hidden;
|
||||
gap: 0.25rem;
|
||||
min-width: 0;
|
||||
margin: 0.75rem 0 0;
|
||||
justify-self: stretch;
|
||||
margin: 0;
|
||||
/* Kein Padding am ul: bei border-box könnte die 0fr-Zeile sonst nicht auf 0
|
||||
kollabieren (ungleiche Abstände). Luft macht das letzte Kind-li. Keine
|
||||
Einrückung — Hierarchie kommt aus Schriftart/-größe und Farbe. */
|
||||
padding: 0;
|
||||
background: none;
|
||||
backdrop-filter: none;
|
||||
border: 0;
|
||||
border-radius: 0;
|
||||
box-shadow: none;
|
||||
text-align: center;
|
||||
text-align: left;
|
||||
transition: opacity var(--transition), visibility var(--transition);
|
||||
}
|
||||
|
||||
.site-nav__item--has-submenu:focus-within > .site-nav__submenu,
|
||||
.site-nav__sublink[aria-expanded="true"] + .site-nav__submenu {
|
||||
display: grid;
|
||||
.site-nav__sublink[aria-expanded="true"] + .site-nav__submenu,
|
||||
.site-nav:not(.site-nav--js) .site-nav__item--has-submenu:focus-within > .site-nav__submenu {
|
||||
opacity: 1;
|
||||
visibility: visible;
|
||||
/* Desktop-Open-Regel (0,3,0) setzt translateX(-50%) — hier neutralisieren,
|
||||
sonst hängt das Untermenü halb aus dem Screen. */
|
||||
transform: none;
|
||||
}
|
||||
|
||||
.site-nav__list .site-nav__submenu > li:last-child {
|
||||
padding-bottom: 0.75rem;
|
||||
}
|
||||
|
||||
/* Unterpunkte in Abel, Groß-/Kleinschreibung — wie im Desktop-Dropdown
|
||||
(Coolvetica-Condensed-Uppercase wird unter 28px unleserlich). Bündig mit
|
||||
den Hauptpunkten; die aktive Unterseite rückt per Desktop-Regel mit
|
||||
Akzentbalken + Tint leicht ein. */
|
||||
.site-nav__list .site-nav__submenu a:not(.btn) {
|
||||
font-size: var(--fs-600);
|
||||
padding: 0.6rem 0.25rem;
|
||||
font-family: var(--ff-body);
|
||||
font-size: var(--fs-500);
|
||||
text-transform: none;
|
||||
color: var(--clr-text-muted);
|
||||
white-space: normal;
|
||||
}
|
||||
|
||||
body.nav-open .site-nav__list {
|
||||
|
||||
@@ -11,6 +11,11 @@
|
||||
return;
|
||||
}
|
||||
|
||||
// Marker fürs CSS: mit JS steuert allein aria-expanded die Dropdowns,
|
||||
// der :focus-within-Fallback (No-JS) wird abgeschaltet (sonst ließe sich
|
||||
// ein Untermenü auf Touch nie wieder zuklappen).
|
||||
toggle.closest('.site-nav').classList.add('site-nav--js');
|
||||
|
||||
var subToggles = Array.prototype.slice.call(list.querySelectorAll('.site-nav__sublink'));
|
||||
|
||||
function closeSubmenus(except) {
|
||||
|
||||
Reference in New Issue
Block a user